diff options
Diffstat (limited to 'src/rexmpp_tcp.c')
-rw-r--r-- | src/rexmpp_tcp.c | 214 |
1 files changed, 119 insertions, 95 deletions
diff --git a/src/rexmpp_tcp.c b/src/rexmpp_tcp.c index e57cfb8..c6a53a5 100644 --- a/src/rexmpp_tcp.c +++ b/src/rexmpp_tcp.c @@ -6,7 +6,6 @@ @copyright MIT license. */ -#include <ares.h> #include <netdb.h> #include <arpa/nameser.h> #include <sys/socket.h> @@ -19,44 +18,42 @@ #include <arpa/inet.h> #include <fcntl.h> +#include "rexmpp.h" #include "rexmpp_tcp.h" +#include "rexmpp_dns.h" -void rexmpp_dns_aaaa_cb (void *ptr, - int status, - int timeouts, - unsigned char *abuf, - int alen) +void rexmpp_tcp_dns_aaaa_cb (rexmpp_t *s, + void *ptr, + rexmpp_dns_result_t *result) { + (void)s; rexmpp_tcp_conn_t *conn = ptr; - conn->resolver_status_v6 = status; - if (status == ARES_SUCCESS) { + conn->resolved_v6 = result; + if (result != NULL) { conn->resolution_v6 = REXMPP_CONN_RESOLUTION_SUCCESS; - ares_parse_aaaa_reply(abuf, alen, &(conn->addr_v6), NULL, NULL); conn->addr_cur_v6 = -1; } else { conn->resolution_v6 = REXMPP_CONN_RESOLUTION_FAILURE; } } -void rexmpp_dns_a_cb (void *ptr, - int status, - int timeouts, - unsigned char *abuf, - int alen) +void rexmpp_tcp_dns_a_cb (rexmpp_t *s, + void *ptr, + rexmpp_dns_result_t *result) { + (void)s; rexmpp_tcp_conn_t *conn = ptr; - conn->resolver_status_v4 = status; - if (status == ARES_SUCCESS) { + conn->resolved_v4 = result; + if (result != NULL) { conn->resolution_v4 = REXMPP_CONN_RESOLUTION_SUCCESS; - ares_parse_a_reply(abuf, alen, &(conn->addr_v4), NULL, NULL); conn->addr_cur_v4 = -1; if (conn->resolution_v6 == REXMPP_CONN_RESOLUTION_WAITING) { /* Wait for 50 ms for IPv6. */ - gettimeofday(&(conn->next_connection_time), NULL); - conn->next_connection_time.tv_usec += REXMPP_TCP_IPV6_DELAY_MS * 1000; - if (conn->next_connection_time.tv_usec >= 1000000) { - conn->next_connection_time.tv_usec -= 1000000; + clock_gettime(CLOCK_MONOTONIC, &(conn->next_connection_time)); + conn->next_connection_time.tv_nsec += REXMPP_TCP_IPV6_DELAY_MS * 1000000; + if (conn->next_connection_time.tv_nsec >= 1000000000) { + conn->next_connection_time.tv_nsec -= 1000000000; conn->next_connection_time.tv_sec++; } } @@ -74,29 +71,52 @@ void rexmpp_tcp_cleanup (rexmpp_tcp_conn_t *conn) { } } if (conn->resolution_v4 != REXMPP_CONN_RESOLUTION_INACTIVE) { - ares_destroy(conn->resolver_channel); conn->resolution_v4 = REXMPP_CONN_RESOLUTION_INACTIVE; conn->resolution_v6 = REXMPP_CONN_RESOLUTION_INACTIVE; } - if (conn->addr_v4 != NULL) { - ares_free_hostent(conn->addr_v4); - conn->addr_v4 = NULL; + if (conn->resolved_v4 != NULL) { + rexmpp_dns_result_free(conn->resolved_v4); + conn->resolved_v4 = NULL; } - if (conn->addr_v6 != NULL) { - ares_free_hostent(conn->addr_v6); - conn->addr_v6 = NULL; + if (conn->resolved_v6 != NULL) { + rexmpp_dns_result_free(conn->resolved_v6); + conn->resolved_v6 = NULL; } } rexmpp_tcp_conn_error_t rexmpp_tcp_connected (rexmpp_tcp_conn_t *conn, int fd) { + struct sockaddr sa; + socklen_t sa_len = sizeof(sa); + getsockname(fd, &sa, &sa_len); + if (sa.sa_family == AF_INET && conn->resolved_v4 != NULL) { + conn->dns_secure = conn->resolved_v4->secure; + } else if (sa.sa_family == AF_INET6 && conn->resolved_v6 != NULL) { + conn->dns_secure = conn->resolved_v6->secure; + } conn->fd = fd; rexmpp_tcp_cleanup(conn); return REXMPP_CONN_DONE; } +int rexmpp_tcp_socket(rexmpp_t *s, int domain) { + int sock = socket(domain, SOCK_STREAM, 0); + + /* Make it non-blocking */ + int flags = fcntl(sock, F_GETFL, 0); + fcntl(sock, F_SETFL, flags | O_NONBLOCK); + + /* Call the socket creation callback, if provided */ + if (s->socket_cb != NULL) { + s->socket_cb(s, sock); + } + + return sock; +} + rexmpp_tcp_conn_error_t -rexmpp_tcp_conn_init (rexmpp_tcp_conn_t *conn, +rexmpp_tcp_conn_init (rexmpp_t *s, + rexmpp_tcp_conn_t *conn, const char *host, uint16_t port) { @@ -106,24 +126,21 @@ rexmpp_tcp_conn_init (rexmpp_tcp_conn_t *conn, } conn->connection_attempts = 0; conn->port = port; - conn->addr_v4 = NULL; - conn->addr_v6 = NULL; + conn->resolved_v4 = NULL; + conn->resolved_v6 = NULL; conn->fd = -1; + conn->dns_secure = 0; conn->next_connection_time.tv_sec = 0; - conn->next_connection_time.tv_usec = 0; + conn->next_connection_time.tv_nsec = 0; conn->resolution_v4 = REXMPP_CONN_RESOLUTION_INACTIVE; conn->resolution_v6 = REXMPP_CONN_RESOLUTION_INACTIVE; struct sockaddr_in addr_v4; - int flags; - if (inet_pton(AF_INET, host, &addr_v4)) { + if (inet_pton(AF_INET, host, &(addr_v4.sin_addr))) { addr_v4.sin_family = AF_INET; addr_v4.sin_port = htons(port); - conn->sockets[conn->connection_attempts] = - socket(AF_INET, SOCK_STREAM, 0); - flags = fcntl(conn->sockets[conn->connection_attempts], F_GETFL, 0); - fcntl(conn->sockets[conn->connection_attempts], F_SETFL, flags | O_NONBLOCK); + conn->sockets[conn->connection_attempts] = rexmpp_tcp_socket(s, AF_INET); if (connect(conn->sockets[conn->connection_attempts], (struct sockaddr*)&addr_v4, sizeof(addr_v4))) { @@ -137,14 +154,13 @@ rexmpp_tcp_conn_init (rexmpp_tcp_conn_t *conn, conn->connection_attempts++; return REXMPP_CONN_IN_PROGRESS; } - struct sockaddr_in addr_v6; - if (inet_pton(AF_INET6, host, &addr_v6)) { - addr_v6.sin_family = AF_INET6; - addr_v6.sin_port = htons(port); - conn->sockets[conn->connection_attempts] = - socket(AF_INET6, SOCK_STREAM, 0); - flags = fcntl(conn->sockets[conn->connection_attempts], F_GETFL, 0); - fcntl(conn->sockets[conn->connection_attempts], F_SETFL, flags | O_NONBLOCK); + struct sockaddr_in6 addr_v6; + if (inet_pton(AF_INET6, host, &(addr_v6.sin6_addr))) { + addr_v6.sin6_family = AF_INET6; + addr_v6.sin6_port = htons(port); + addr_v6.sin6_flowinfo = 0; + addr_v6.sin6_scope_id = 0; + conn->sockets[conn->connection_attempts] = rexmpp_tcp_socket(s, AF_INET6); if (connect(conn->sockets[conn->connection_attempts], (struct sockaddr*)&addr_v6, sizeof(addr_v6))) { @@ -160,15 +176,11 @@ rexmpp_tcp_conn_init (rexmpp_tcp_conn_t *conn, } conn->resolution_v4 = REXMPP_CONN_RESOLUTION_WAITING; conn->resolution_v6 = REXMPP_CONN_RESOLUTION_WAITING; - conn->resolver_error = ares_init(&(conn->resolver_channel)); - if (conn->resolver_error != ARES_SUCCESS) { - return REXMPP_CONN_RESOLVER_ERROR; - } - ares_query(conn->resolver_channel, host, - ns_c_in, ns_t_aaaa, rexmpp_dns_aaaa_cb, conn); - ares_query(conn->resolver_channel, host, - ns_c_in, ns_t_a, rexmpp_dns_a_cb, conn); + rexmpp_dns_resolve(s, host, 28, 1, + conn, rexmpp_tcp_dns_aaaa_cb); + rexmpp_dns_resolve(s, host, 1, 1, + conn, rexmpp_tcp_dns_a_cb); return REXMPP_CONN_IN_PROGRESS; } @@ -180,22 +192,24 @@ int rexmpp_tcp_conn_finish (rexmpp_tcp_conn_t *conn) { int rexmpp_tcp_conn_ipv4_available(rexmpp_tcp_conn_t *conn) { return (conn->resolution_v4 == REXMPP_CONN_RESOLUTION_SUCCESS && - conn->addr_v4 != NULL && - conn->addr_v4->h_addr_list[conn->addr_cur_v4 + 1] != NULL); + conn->resolved_v4 != NULL && + conn->resolved_v4->data[conn->addr_cur_v4 + 1] != NULL); } int rexmpp_tcp_conn_ipv6_available(rexmpp_tcp_conn_t *conn) { return (conn->resolution_v6 == REXMPP_CONN_RESOLUTION_SUCCESS && - conn->addr_v6 != NULL && - conn->addr_v6->h_addr_list[conn->addr_cur_v6 + 1] != NULL); + conn->resolved_v6 != NULL && + conn->resolved_v6->data[conn->addr_cur_v6 + 1] != NULL); } rexmpp_tcp_conn_error_t -rexmpp_tcp_conn_proceed (rexmpp_tcp_conn_t *conn, +rexmpp_tcp_conn_proceed (rexmpp_t *s, + rexmpp_tcp_conn_t *conn, fd_set *read_fds, fd_set *write_fds) { - struct timeval now; + (void)read_fds; /* Not checking any read FDs at the moment. */ + struct timespec now; int i; /* Check for successful connections. */ @@ -219,7 +233,7 @@ rexmpp_tcp_conn_proceed (rexmpp_tcp_conn_t *conn, /* Name resolution. */ if (conn->resolution_v4 == REXMPP_CONN_RESOLUTION_WAITING || conn->resolution_v6 == REXMPP_CONN_RESOLUTION_WAITING) { - ares_process(conn->resolver_channel, read_fds, write_fds); + rexmpp_dns_process(s, read_fds, write_fds); } if (conn->resolution_v4 == REXMPP_CONN_RESOLUTION_FAILURE && @@ -235,10 +249,10 @@ rexmpp_tcp_conn_proceed (rexmpp_tcp_conn_t *conn, if (conn->connection_attempts < REXMPP_TCP_MAX_CONNECTION_ATTEMPTS && (rexmpp_tcp_conn_ipv4_available(conn) || rexmpp_tcp_conn_ipv6_available(conn))) { - gettimeofday(&now, NULL); + clock_gettime(CLOCK_MONOTONIC, &now); if (now.tv_sec > conn->next_connection_time.tv_sec || (now.tv_sec == conn->next_connection_time.tv_sec && - now.tv_usec >= conn->next_connection_time.tv_usec)) { + now.tv_nsec >= conn->next_connection_time.tv_nsec)) { /* Time to attempt a new connection. */ int use_ipv6 = 0; if (rexmpp_tcp_conn_ipv4_available(conn) && @@ -255,39 +269,47 @@ rexmpp_tcp_conn_proceed (rexmpp_tcp_conn_t *conn, struct sockaddr *addr; socklen_t addrlen; int domain; + int len; if (use_ipv6) { conn->addr_cur_v6++; + len = sizeof(addr_v6.sin6_addr); + if (len > conn->resolved_v6->len[conn->addr_cur_v6]) { + len = conn->resolved_v6->len[conn->addr_cur_v6]; + } memcpy(&addr_v6.sin6_addr, - conn->addr_v6->h_addr_list[conn->addr_cur_v6], - conn->addr_v6->h_length); - addr_v6.sin6_family = conn->addr_v6->h_addrtype; + conn->resolved_v6->data[conn->addr_cur_v6], + len); + addr_v6.sin6_family = AF_INET6; addr_v6.sin6_port = htons(conn->port); - domain = conn->addr_v6->h_addrtype; + addr_v6.sin6_flowinfo = 0; + addr_v6.sin6_scope_id = 0; + domain = AF_INET6; addr = (struct sockaddr*)&addr_v6; addrlen = sizeof(addr_v6); } else { conn->addr_cur_v4++; + len = sizeof(addr_v4.sin_addr); + if (len > conn->resolved_v4->len[conn->addr_cur_v4]) { + len = conn->resolved_v4->len[conn->addr_cur_v4]; + } memcpy(&addr_v4.sin_addr, - conn->addr_v4->h_addr_list[conn->addr_cur_v4], - conn->addr_v4->h_length); - addr_v4.sin_family = conn->addr_v4->h_addrtype; + conn->resolved_v4->data[conn->addr_cur_v4], + len); + addr_v4.sin_family = AF_INET; addr_v4.sin_port = htons(conn->port); - domain = conn->addr_v4->h_addrtype; + domain = AF_INET; addr = (struct sockaddr*)&addr_v4; addrlen = sizeof(addr_v4); } - conn->sockets[conn->connection_attempts] = - socket(domain, SOCK_STREAM, 0); - int flags = fcntl(conn->sockets[conn->connection_attempts], F_GETFL, 0); - fcntl(conn->sockets[conn->connection_attempts], F_SETFL, flags | O_NONBLOCK); + conn->sockets[conn->connection_attempts] = rexmpp_tcp_socket(s, domain); if (connect(conn->sockets[conn->connection_attempts], addr, addrlen)) { if (errno == EINPROGRESS) { - gettimeofday(&(conn->next_connection_time), NULL); - conn->next_connection_time.tv_usec += REXMPP_TCP_CONN_DELAY_MS * 1000; - if (conn->next_connection_time.tv_usec >= 1000000) { - conn->next_connection_time.tv_usec -= 1000000; + clock_gettime(CLOCK_MONOTONIC, &(conn->next_connection_time)); + conn->next_connection_time.tv_nsec += REXMPP_TCP_CONN_DELAY_MS * 1000000; + if (conn->next_connection_time.tv_nsec >= 1000000000) { + conn->next_connection_time.tv_nsec -= 1000000000; conn->next_connection_time.tv_sec++; } conn->connection_attempts++; @@ -316,28 +338,29 @@ rexmpp_tcp_conn_proceed (rexmpp_tcp_conn_t *conn, } } - gettimeofday(&now, NULL); + clock_gettime(CLOCK_MONOTONIC, &now); if (active_connections || conn->resolution_v4 == REXMPP_CONN_RESOLUTION_WAITING || conn->resolution_v6 == REXMPP_CONN_RESOLUTION_WAITING || (conn->next_connection_time.tv_sec > now.tv_sec || (conn->next_connection_time.tv_sec == now.tv_sec && - conn->next_connection_time.tv_usec > now.tv_usec))) { + conn->next_connection_time.tv_nsec > now.tv_nsec))) { return REXMPP_CONN_IN_PROGRESS; } else { return REXMPP_CONN_FAILURE; } } -int rexmpp_tcp_conn_fds (rexmpp_tcp_conn_t *conn, +int rexmpp_tcp_conn_fds (rexmpp_t *s, + rexmpp_tcp_conn_t *conn, fd_set *read_fds, fd_set *write_fds) { int max_fd = 0, i; if (conn->resolution_v4 == REXMPP_CONN_RESOLUTION_WAITING || conn->resolution_v6 == REXMPP_CONN_RESOLUTION_WAITING) { - max_fd = ares_fds(conn->resolver_channel, read_fds, write_fds); + max_fd = rexmpp_dns_fds(s, read_fds, write_fds); } for (i = 0; i < REXMPP_TCP_MAX_CONNECTION_ATTEMPTS; i++) { if (conn->sockets[i] != -1) { @@ -350,34 +373,35 @@ int rexmpp_tcp_conn_fds (rexmpp_tcp_conn_t *conn, return max_fd; } -struct timeval *rexmpp_tcp_conn_timeout (rexmpp_tcp_conn_t *conn, - struct timeval *max_tv, - struct timeval *tv) +struct timespec *rexmpp_tcp_conn_timeout (rexmpp_t *s, + rexmpp_tcp_conn_t *conn, + struct timespec *max_tv, + struct timespec *tv) { - struct timeval now; - struct timeval *ret = max_tv; + struct timespec now; + struct timespec *ret = max_tv; if (conn->resolution_v4 == REXMPP_CONN_RESOLUTION_WAITING || conn->resolution_v6 == REXMPP_CONN_RESOLUTION_WAITING) { - ret = ares_timeout(conn->resolver_channel, max_tv, tv); + ret = rexmpp_dns_timeout(s, max_tv, tv); } if (conn->resolution_v4 == REXMPP_CONN_RESOLUTION_SUCCESS || conn->resolution_v6 == REXMPP_CONN_RESOLUTION_SUCCESS || (conn->resolution_v4 == REXMPP_CONN_RESOLUTION_INACTIVE && conn->resolution_v6 == REXMPP_CONN_RESOLUTION_INACTIVE)) { - gettimeofday(&now, NULL); + clock_gettime(CLOCK_MONOTONIC, &now); if (now.tv_sec < conn->next_connection_time.tv_sec || (now.tv_sec == conn->next_connection_time.tv_sec && - now.tv_usec <= conn->next_connection_time.tv_usec)) { + now.tv_nsec <= conn->next_connection_time.tv_nsec)) { if (ret == NULL || ret->tv_sec > conn->next_connection_time.tv_sec - now.tv_sec || (ret->tv_sec == conn->next_connection_time.tv_sec - now.tv_sec && - ret->tv_usec > conn->next_connection_time.tv_usec - now.tv_usec)) { + ret->tv_nsec > conn->next_connection_time.tv_nsec - now.tv_nsec)) { ret = tv; tv->tv_sec = conn->next_connection_time.tv_sec - now.tv_sec; - if (conn->next_connection_time.tv_usec > now.tv_usec) { - tv->tv_usec = conn->next_connection_time.tv_usec - now.tv_usec; + if (conn->next_connection_time.tv_nsec > now.tv_nsec) { + tv->tv_nsec = conn->next_connection_time.tv_nsec - now.tv_nsec; } else { - tv->tv_usec = conn->next_connection_time.tv_usec + 1000000 - now.tv_usec; + tv->tv_nsec = conn->next_connection_time.tv_nsec + 1000000000 - now.tv_nsec; tv->tv_sec--; } } |