From 2d9e630a430e079ec30f674de1abbd7f4a186657 Mon Sep 17 00:00:00 2001 From: sr Date: Tue, 15 Jan 2013 17:57:27 +0100 Subject: [SERVER] Add IPv6 support (clients and RPC connections) --- src/server/sockhelper.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 156 insertions(+), 3 deletions(-) (limited to 'src/server/sockhelper.c') diff --git a/src/server/sockhelper.c b/src/server/sockhelper.c index c72c74f..4c7c45b 100644 --- a/src/server/sockhelper.c +++ b/src/server/sockhelper.c @@ -1,6 +1,11 @@ #include "sockhelper.h" +#include "memlog.h" #include #include +#include +#include +#include +#include static inline int connect_shared(const int client_sock, void* addr, const int addrlen, int connect_ms, int rw_ms) { @@ -10,8 +15,10 @@ static inline int connect_shared(const int client_sock, void* addr, const int ad tv.tv_usec = connect_ms * 1000; setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); setsockopt(client_sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); - if (connect(client_sock, (struct sockaddr *)&addr, addrlen) == -1) + if (connect(client_sock, (struct sockaddr *)addr, addrlen) == -1) { + //int e = errno; + //printf("connect -1 (%d)\n", e); return -1; } // Apply read/write timeout @@ -31,9 +38,14 @@ int sock_connect4(struct sockaddr_in *addr, const int connect_ms, const int rw_m int sock_connect6(struct sockaddr_in6 *addr, const int connect_ms, const int rw_ms) { +#ifdef WITH_IPV6 int client_sock = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP); if (client_sock == -1) return -1; return connect_shared(client_sock, addr, sizeof(struct sockaddr_in6), connect_ms, rw_ms); +#else + printf("[DEBUG] Not compiled with IPv6 support.\n"); + return -1; +#endif } int sock_connect(const dnbd3_host_t * const addr, const int connect_ms, const int rw_ms) @@ -44,21 +56,162 @@ int sock_connect(const dnbd3_host_t * const addr, const int connect_ms, const in struct sockaddr_in addr4; memset(&addr4, 0, sizeof(addr4)); addr4.sin_family = AF_INET; - memcpy(&addr4.sin_addr.s_addr, addr->addr, 4); + memcpy(&addr4.sin_addr, addr->addr, 4); addr4.sin_port = addr->port; return sock_connect4(&addr4, connect_ms, rw_ms); } +#ifdef WITH_IPV6 else if (addr->type == AF_INET6) { // Set host (IPv6) struct sockaddr_in6 addr6; memset(&addr6, 0, sizeof(addr6)); addr6.sin6_family = AF_INET6; - memcpy(&addr6.sin6_addr.s6_addr, addr->addr, 16); + memcpy(&addr6.sin6_addr, addr->addr, 16); addr6.sin6_port = addr->port; return sock_connect6(&addr6, connect_ms, rw_ms); } +#endif printf("[DEBUG] Unsupported address type: %d\n", (int)addr->type); return -1; } +void sock_set_timeout(const int sockfd, const int milliseconds) +{ + struct timeval tv; + tv.tv_sec = milliseconds / 1000; + tv.tv_usec = milliseconds * 1000; + setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); +} + +int sock_listen_any(int protocol_family, uint16_t port) +{ + struct sockaddr_storage addr; + memset(&addr, 0, sizeof(addr)); + if (protocol_family == PF_INET) + { + struct sockaddr_in *v4 = (struct sockaddr_in *)&addr; + v4->sin_addr.s_addr = INADDR_ANY; + v4->sin_port = htons(port); + v4->sin_family = AF_INET; + } +#ifdef WITH_IPV6 + else if (protocol_family == PF_INET6) + { + struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)&addr; + v6->sin6_addr = in6addr_any; + v6->sin6_port = htons(port); + v6->sin6_family = AF_INET6; + } +#endif + else + { + printf("[DEBUG] sock_listen: Unsupported protocol: %d\n", protocol_family); + return -1; + } + return sock_listen(&addr, sizeof(addr)); +} + +int sock_listen(struct sockaddr_storage *addr, int addrlen) +{ + int pf; // On Linux AF_* == PF_*, but this is not guaranteed on all platforms, so let's be safe here: + if (addr->ss_family == AF_INET) + pf = PF_INET; +#ifdef WITH_IPV6 + else if (addr->ss_family == AF_INET6) + pf = PF_INET6; +#endif + else + { + printf("[DEBUG] sock_listen: unsupported address type: %d\n", (int)addr->ss_family); + return -1; + } + int sock; + + // Create socket + sock = socket(pf, SOCK_STREAM, IPPROTO_TCP); + if (sock < 0) + { + memlogf("[ERROR] sock_listen: Socket setup failure"); // TODO: print port number to help troubleshooting + return -1; + } + const int on = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (pf == PF_INET6) + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); + + // Bind to socket + if (bind(sock, (struct sockaddr *) addr, addrlen) < 0) + { + int e = errno; + close(sock); + memlogf("[ERROR] Bind failure (%d)", e); // TODO: print port number to help troubleshooting + return -1; + } + + // Listen on socket + if (listen(sock, 20) == -1) + { + close(sock); + memlogf("[ERROR] Listen failure"); // TODO ... + return -1; + } + + return sock; +} + +int accept_any(const int * const sockets, const int socket_count, struct sockaddr_storage *addr, socklen_t *length_ptr) +{ + fd_set set; + FD_ZERO(&set); + int max = 0; + for (int i = 0; i < socket_count; ++i) + { + FD_SET(sockets[i], &set); + if (sockets[i] > max) + max = sockets[i]; + } + if (select(max + 1, &set, NULL, NULL, NULL) <= 0) return -1; + for (int i = 0; i < socket_count; ++i) + { + if (FD_ISSET(sockets[i], &set)) + return accept(sockets[i], (struct sockaddr *)addr, length_ptr); + } + return -1; +} + +void sock_set_nonblock(int sock) +{ + int flags = fcntl(sock, F_GETFL, 0); + if (flags == -1) + flags = 0; + fcntl(sock, F_SETFL, flags | O_NONBLOCK); +} + +void sock_set_block(int sock) +{ + int flags = fcntl(sock, F_GETFL, 0); + if (flags == -1) + flags = 0; + fcntl(sock, F_SETFL, flags & ~(int)O_NONBLOCK); +} + +int sock_add_array(const int sock, int *array, int *array_fill, const int array_length) +{ + if (sock == -1) + return TRUE; + for (int i = 0; i < *array_fill; ++i) + { + if (array[i] == -1) + { + array[i] = sock; + return TRUE; + } + } + if (*array_fill >= array_length) + return FALSE; + array[*array_fill] = sock; + (*array_fill) += 1; + return TRUE; +} -- cgit v1.2.3-55-g7522