summaryrefslogtreecommitdiffstats
path: root/src/server/sockhelper.c
diff options
context:
space:
mode:
authorsr2013-01-15 17:57:27 +0100
committersr2013-01-15 17:57:27 +0100
commit2d9e630a430e079ec30f674de1abbd7f4a186657 (patch)
treeefb3f67a04a7dcc1f6889398a78059e31227c50b /src/server/sockhelper.c
parent[SERVER] Add socket helper module to simplify connection setup (diff)
downloaddnbd3-2d9e630a430e079ec30f674de1abbd7f4a186657.tar.gz
dnbd3-2d9e630a430e079ec30f674de1abbd7f4a186657.tar.xz
dnbd3-2d9e630a430e079ec30f674de1abbd7f4a186657.zip
[SERVER] Add IPv6 support (clients and RPC connections)
Diffstat (limited to 'src/server/sockhelper.c')
-rw-r--r--src/server/sockhelper.c159
1 files changed, 156 insertions, 3 deletions
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 <string.h>
#include <stdio.h>
+#include <glib/gmacros.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
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;
+}