summaryrefslogtreecommitdiff
path: root/src/rexmpp_tcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rexmpp_tcp.c')
-rw-r--r--src/rexmpp_tcp.c214
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--;
}
}