diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/IO/http.c | 79 |
1 files changed, 63 insertions, 16 deletions
diff --git a/src/IO/http.c b/src/IO/http.c index d8fcf018..30b36eb4 100644 --- a/src/IO/http.c +++ b/src/IO/http.c @@ -27,6 +27,7 @@ #include <arpa/inet.h> /* for inet_ntop */ #include "IO.h" +#include "iowatch.hh" #include "tls.h" #include "Url.h" #include "../msg.h" @@ -53,6 +54,7 @@ static const int HTTP_SOCKET_USE_PROXY = 0x1; static const int HTTP_SOCKET_QUEUED = 0x2; static const int HTTP_SOCKET_TO_BE_FREED = 0x4; static const int HTTP_SOCKET_TLS = 0x8; +static const int HTTP_SOCKET_IOWATCH_ACTIVE = 0x10; /* 'web' is just a reference (no need to deallocate it here). */ typedef struct { @@ -296,6 +298,10 @@ static void Http_socket_free(int SKey) if ((S = a_Klist_get_data(ValidSocks, SKey))) { a_Klist_remove(ValidSocks, SKey); + if (S->flags & HTTP_SOCKET_IOWATCH_ACTIVE) { + S->flags &= ~HTTP_SOCKET_IOWATCH_ACTIVE; + a_IOwatch_remove_fd(S->SockFD, -1); + } dStr_free(S->https_proxy_reply, 1); if (S->flags & HTTP_SOCKET_QUEUED) { @@ -479,9 +485,7 @@ static void Http_send_query(SocketData_t *S) query = Http_make_query_str(S->web, S->flags & HTTP_SOCKET_USE_PROXY); dbuf = a_Chain_dbuf_new(query->str, query->len, 0); - /* actually this message is sent too early. - * It should go when the socket is ready for writing (i.e. connected) */ - _MSG_BW(S->web, 1, "Sending query to %s...", URL_HOST_(S->web->url)); + MSG_BW(S->web, 1, "Sending query..."); /* send query */ a_Chain_bcb(OpSend, S->Info, dbuf, NULL); @@ -509,18 +513,53 @@ static void Http_connect_tls(ChainLink *info) dFree(dbuf); dFree(connect_str); } else { + MSG_BW(S->web, 1, "TLS handshake..."); a_Tls_handshake(S->SockFD, S->url); } } /* + * connect() couldn't complete before, but now it's ready, so let's try again. + */ +static void Http_connect_socket_cb(int fd, void *data) +{ + int SKey = VOIDP2INT(data); + SocketData_t *S = a_Klist_get_data(ValidSocks, SKey); + + if (S) { + int ret, connect_ret; + uint_t connect_ret_size = sizeof(connect_ret); + + a_IOwatch_remove_fd(fd, -1); + S->flags &= ~HTTP_SOCKET_IOWATCH_ACTIVE; + + ret = getsockopt(S->SockFD, SOL_SOCKET, SO_ERROR, &connect_ret, + &connect_ret_size); + + if (ret < 0 || connect_ret != 0) { + if (ret < 0) { + MSG("Http_connect_socket_cb getsockopt ERROR: %s.\n", + dStrerror(errno)); + } else { + MSG("Http_connect_socket_cb connect ERROR: %s.\n", + dStrerror(connect_ret)); + } + a_Http_connect_done(S->SockFD, FALSE); + } else if (S->flags & HTTP_SOCKET_TLS) { + Http_connect_tls(S->Info); + } else { + a_Http_connect_done(S->SockFD, TRUE); + } + } +} + +/* * This function is called after the DNS succeeds in solving a hostname. * Task: Finish socket setup and start connecting the socket. */ static void Http_connect_socket(ChainLink *Info) { - int i, status; - SocketData_t *S; + int i; DilloHost *dh; #ifdef ENABLE_IPV6 struct sockaddr_in6 name; @@ -528,13 +567,12 @@ static void Http_connect_socket(ChainLink *Info) struct sockaddr_in name; #endif socklen_t socket_len = 0; - - S = a_Klist_get_data(ValidSocks, VOIDP2INT(Info->LocalKey)); + SocketData_t *S = a_Klist_get_data(ValidSocks, VOIDP2INT(Info->LocalKey)); /* TODO: iterate this address list until success, or end-of-list */ for (i = 0; (dh = dList_nth_data(S->addr_list, i)); ++i) { if ((S->SockFD = socket(dh->af, SOCK_STREAM, IPPROTO_TCP)) < 0) { - MSG("Http_connect_socket ERROR: %s\n", dStrerror(errno)); + MSG("Http_connect_socket socket() ERROR: %s\n", dStrerror(errno)); continue; } Http_fd_map_add_entry(S); @@ -574,16 +612,25 @@ static void Http_connect_socket(ChainLink *Info) break; } #endif - }/*switch*/ + } /* switch */ MSG_BW(S->web, 1, "Contacting host..."); - status = connect(S->SockFD, (struct sockaddr *)&name, socket_len); - if (status == -1 && errno != EINPROGRESS) { - MSG("Http_connect_socket ERROR: %s\n", dStrerror(errno)); - a_Http_connect_done(S->SockFD, FALSE); - } else if (S->flags & HTTP_SOCKET_TLS) { - Http_connect_tls(Info); + + if (connect(S->SockFD, (struct sockaddr *)&name, socket_len) == 0) { + /* probably never succeeds immediately on any system */ + if (S->flags & HTTP_SOCKET_TLS) { + Http_connect_tls(Info); + } else { + a_Http_connect_done(S->SockFD, TRUE); + } } else { - a_Http_connect_done(S->SockFD, TRUE); + if (errno == EINPROGRESS) { + a_IOwatch_add_fd(S->SockFD, DIO_WRITE, Http_connect_socket_cb, + Info->LocalKey); + S->flags |= HTTP_SOCKET_IOWATCH_ACTIVE; + } else { + MSG("Http_connect_socket connect ERROR: %s\n", dStrerror(errno)); + a_Http_connect_done(S->SockFD, FALSE); + } } return; } |