Mercurial > dropbear
diff dbutil.c @ 1025:02baa0b334e8 fastopen
async connections working
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Wed, 18 Feb 2015 22:46:15 +0800 |
parents | aac0095dc3b4 |
children | daf21fd50abf |
line wrap: on
line diff
--- a/dbutil.c Wed Feb 18 00:05:27 2015 +0800 +++ b/dbutil.c Wed Feb 18 22:46:15 2015 +0800 @@ -995,6 +995,8 @@ or NULL. */ int sock; + + char* errstring; }; /* Deallocate a progress connection. Removes from the pending list if iter!=NULL. @@ -1005,6 +1007,7 @@ } m_free(c->remotehost); m_free(c->remoteport); + m_free(c->errstring); m_free(c); if (iter) { @@ -1012,12 +1015,24 @@ } } -static int connect_try_next(struct dropbear_progress_connection *c) { +static void cancel_callback(int result, int sock, void* UNUSED(data), const char* UNUSED(errstring)) { + if (result == DROPBEAR_SUCCESS) + { + m_close(sock); + } +} + +void cancel_connect(struct dropbear_progress_connection *c) { + c->cb = cancel_callback; + c->cb_data = NULL; +} + +static void connect_try_next(struct dropbear_progress_connection *c) { int err = EADDRNOTAVAIL; struct addrinfo *r; if (!c->res_iter) { - return DROPBEAR_FAILURE; + return; } for (r = c->res_iter; r; r = r->ai_next) @@ -1030,6 +1045,7 @@ continue; } + ses.maxfd = MAX(ses.maxfd, c->sock); setnonblocking(c->sock); #if defined(__linux__) && defined(TCP_DEFER_ACCEPT) @@ -1060,8 +1076,12 @@ if (c->sock >= 0 || (errno == EINPROGRESS)) { /* Success */ set_sock_nodelay(c->sock); - return DROPBEAR_SUCCESS; + return; } else { + if (!c->res_iter) + { + + } /* XXX - returning error message through */ #if 0 /* Failed */ @@ -1073,15 +1093,10 @@ } TRACE(("Error connecting: %s", strerror(err))) #endif - return DROPBEAR_FAILURE; } } -/* Connect via TCP to a host. Connection will try ipv4 or ipv6, will - * return immediately if nonblocking is set. On failure, if errstring - * wasn't null, it will be a newly malloced error message */ - -/* TODO: maxfd */ +/* Connect via TCP to a host. */ struct dropbear_progress_connection *connect_remote(const char* remotehost, const char* remoteport, connect_callback cb, void* cb_data) { @@ -1096,6 +1111,8 @@ c->cb = cb; c->cb_data = cb_data; + list_append(&ses.conn_pending, c); + memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = PF_UNSPEC; @@ -1103,29 +1120,18 @@ err = getaddrinfo(remotehost, remoteport, &hints, &c->res); if (err) { int len; - char *errstring; len = 100 + strlen(gai_strerror(err)); - errstring = (char*)m_malloc(len); - snprintf(errstring, len, "Error resolving '%s' port '%s'. %s", + c->errstring = (char*)m_malloc(len); + snprintf(c->errstring, len, "Error resolving '%s' port '%s'. %s", remotehost, remoteport, gai_strerror(err)); - c->cb(DROPBEAR_FAILURE, -1, c->cb_data, errstring); - m_free(errstring); TRACE(("Error resolving: %s", gai_strerror(err))) - remove_connect(c, NULL); return NULL; } c->res_iter = c->res; - if (connect_try_next(c) == DROPBEAR_FAILURE) { - /* Should not happen - getaddrinfo() should return failure if there are no addresses */ - c->cb(DROPBEAR_FAILURE, -1, c->cb_data, "No address to try"); - TRACE(("leave handle_connect_fds - failed")) - remove_connect(c, NULL); - return NULL; - } - - list_append(&ses.conn_pending, c); + /* Set one going */ + connect_try_next(c); return c; } @@ -1136,12 +1142,24 @@ TRACE(("enter handle_connect_fds")) for (iter = ses.conn_pending.first; iter; iter = iter->next) { struct dropbear_progress_connection *c = iter->item; + /* Set one going */ + while (c->res_iter && c->sock < 0) + { + connect_try_next(c); + } if (c->sock >= 0) { FD_SET(c->sock, writefd); - } - else - { - + } else { + m_list_elem *remove_iter; + /* Final failure */ + if (!c->errstring) { + c->errstring = m_strdup("unexpected failure"); + } + c->cb(DROPBEAR_FAILURE, -1, c->cb_data, c->errstring); + /* Safely remove without invalidating iter */ + remove_iter = iter; + iter = iter->prev; + remove_connect(c, remove_iter); } } } @@ -1162,31 +1180,25 @@ if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &val, &vallen) != 0) { TRACE(("handle_connect_fds getsockopt(%d) SO_ERROR failed: %s", c->sock, strerror(errno))) + /* This isn't expected to happen - Unix has surprises though, continue gracefully. */ + m_close(c->sock); + c->sock = -1; } else if (val != 0) { /* Connect failed */ TRACE(("connect to %s port %s failed.", c->remotehost, c->remoteport)) m_close(c->sock); c->sock = -1; - if (connect_try_next(c) == DROPBEAR_FAILURE) { - c->cb(DROPBEAR_FAILURE, -1, c->cb_data, strerror(val)); - TRACE(("leave handle_connect_fds - failed")) - remove_connect(c, iter); - /* Must return here - remove_connect() invalidates iter */ - return; - } else { - /* new connection try was successfuly started, will be finished by a - later call to handle_connect_fds() */ - TRACE(("leave handle_connect_fds - new try")) - continue; - } + m_free(c->errstring); + c->errstring = strerror(val); + } else { + /* New connection has been established */ + c->cb(DROPBEAR_SUCCESS, c->sock, c->cb_data, NULL); + remove_connect(c, iter); + TRACE(("leave handle_connect_fds - success")) + /* Must return here - remove_connect() invalidates iter */ + return; } - /* New connection has been established */ - c->cb(DROPBEAR_SUCCESS, c->sock, c->cb_data, ""); - remove_connect(c, iter); - TRACE(("leave handle_connect_fds - success")) - /* Must return here - remove_connect() invalidates iter */ - return; } TRACE(("leave handle_connect_fds - end iter")) }