summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsr2013-01-15 19:02:07 +0100
committersr2013-01-15 19:02:07 +0100
commitc6e1675108df5e3fc9f4e48d0909416753023d3e (patch)
tree318a5412c4ff3dda2fd44aa9c175725679732885
parent[SERVER] Remove old TODO note (diff)
downloaddnbd3-sr-thesis-final.tar.gz
dnbd3-sr-thesis-final.tar.xz
dnbd3-sr-thesis-final.zip
[KERNEL/CLIENT] Add IPv6 supportdnbd3-sr-thesis-final
-rw-r--r--src/client/client.c102
-rw-r--r--src/kernel/net.c90
-rw-r--r--src/server/saveload.c1
3 files changed, 151 insertions, 42 deletions
diff --git a/src/client/client.c b/src/client/client.c
index 397ac38..bd28d51 100644
--- a/src/client/client.c
+++ b/src/client/client.c
@@ -59,26 +59,101 @@ void dnbd3_print_version()
exit(EXIT_SUCCESS);
}
-static void dnbd3_get_ip(char *hostname, uint8_t *target, uint8_t *addrtype)
+/**
+ * Parse IPv4 or IPv6 address in string representation to a suitable format usable by the BSD socket library
+ * @string eg. "1.2.3.4" or "2a01::10:5", optially with port appended, eg "1.2.3.4:6666" or "[2a01::10:5]:6666"
+ * @af will contain either AF_INET or AF_INET6
+ * @addr will contain the address in network representation
+ * @port will contain the port in network representation, defaulting to #define PORT if none was given
+ * returns 1 on success, 0 in failure. contents of af, addr and port are undefined in the latter case
+ * !! Contents of @string might be modified by this function !!
+ */
+static char parse_address(char *string, dnbd3_host_t *host)
{
- struct hostent *host;
+ struct in_addr v4;
+ struct in6_addr v6;
+
+ // Try IPv4 without port
+ if (1 == inet_pton(AF_INET, string, &v4))
+ {
+ host->type = AF_INET;
+ memcpy(host->addr, &v4, 4);
+ host->port = htons(PORT);
+ return 1;
+ }
+ // Try IPv6 without port
+ if (1 == inet_pton(AF_INET6, string, &v6))
+ {
+ host->type = AF_INET6;
+ memcpy(host->addr, &v6, 16);
+ host->port = htons(PORT);
+ return 1;
+ }
+
+ // Scan for port
+ char *portpos = NULL, *ptr = string;
+ while (*ptr)
+ {
+ if (*ptr == ':')
+ portpos = ptr;
+ ++ptr;
+ }
+ if (portpos == NULL)
+ return 0; // No port in string
+ // Consider IP being surrounded by [ ]
+ if (*string == '[' && *(portpos - 1) == ']')
+ {
+ ++string;
+ *(portpos - 1) = '\0';
+ }
+ *portpos++ = '\0';
+ int p = atoi(portpos);
+ if (p < 1 || p > 65535)
+ return 0; // Invalid port
+ host->port = htons((uint16_t)p);
+
+ // Try IPv4 with port
+ if (1 == inet_pton(AF_INET, string, &v4))
+ {
+ host->type = AF_INET;
+ memcpy(host->addr, &v4, 4);
+ return 1;
+ }
+ // Try IPv6 with port
+ if (1 == inet_pton(AF_INET6, string, &v6))
+ {
+ host->type = AF_INET6;
+ memcpy(host->addr, &v6, 16);
+ return 1;
+ }
+
+ // FAIL
+ return 0;
+}
- if ((host = gethostbyname(hostname)) == NULL)
+static void dnbd3_get_ip(char *hostname, dnbd3_host_t *host)
+{
+ if (parse_address(hostname, host))
+ return;
+ // TODO: Parse port too for host names
+ struct hostent *hent;
+ if ((hent = gethostbyname(hostname)) == NULL)
{
printf("FATAL: Unknown host '%s'\n", hostname);
exit(EXIT_FAILURE);
}
- *addrtype = (uint8_t)host->h_addrtype;
- if (host->h_addrtype == AF_INET)
- memcpy(target, host->h_addr, 4);
- else if (host->h_addrtype == AF_INET6)
- memcpy(target, host->h_addr, 16);
+ host->type = (uint8_t)hent->h_addrtype;
+ if (hent->h_addrtype == AF_INET)
+ memcpy(host->addr, hent->h_addr, 4);
+ else if (hent->h_addrtype == AF_INET6)
+ memcpy(host->addr, hent->h_addr, 16);
else
{
- printf("FATAL: Unknown address type: %d\n", host->h_addrtype);
+ printf("FATAL: Unknown address type: %d\n", hent->h_addrtype);
exit(EXIT_FAILURE);
}
+ host->port = htons(PORT);
}
int main(int argc, char *argv[])
@@ -125,8 +200,7 @@ int main(int argc, char *argv[])
_config_file_name = strdup(optarg);
break;
case 'h':
- dnbd3_get_ip(optarg, msg.host.addr, &msg.host.type);
- printf("Host set to %s (type %d)\n", inet_ntoa(*(struct in_addr *)msg.host.addr), (int)msg.host.type);
+ dnbd3_get_ip(optarg, &msg.host);
break;
case 'i':
msg.imgname = strdup(optarg);
@@ -147,7 +221,7 @@ int main(int argc, char *argv[])
close_dev = 1;
break;
case 's':
- dnbd3_get_ip(optarg, msg.host.addr, &msg.host.type);
+ dnbd3_get_ip(optarg, &msg.host);
switch_host = 1;
break;
case 'H':
@@ -215,7 +289,7 @@ int main(int argc, char *argv[])
exit(EXIT_SUCCESS);
}
- // use configuration file if exist
+ // use configuration file if existent
GKeyFile *gkf;
int i = 0;
size_t j = 0;
@@ -229,7 +303,7 @@ int main(int argc, char *argv[])
for (i = 0; i < j; i++)
{
- dnbd3_get_ip(g_key_file_get_string(gkf, groups[i], "server", NULL), msg.host.addr, &msg.host.type);
+ dnbd3_get_ip(g_key_file_get_string(gkf, groups[i], "server", NULL), &msg.host);
msg.imgname = g_key_file_get_string(gkf, groups[i], "name", NULL);
msg.rid = g_key_file_get_integer(gkf, groups[i], "rid", NULL);
dev = g_key_file_get_string(gkf, groups[i], "device", NULL);
diff --git a/src/kernel/net.c b/src/kernel/net.c
index f225189..0217d26 100644
--- a/src/kernel/net.c
+++ b/src/kernel/net.c
@@ -67,13 +67,13 @@
#else // Silent
-#define debug_dev(x) while(0)
+#define debug_dev(x) do { } while(0)
#define error_dev(x) goto error
-#define debug_dev_va(x, ...) while(0)
+#define debug_dev_va(x, ...) do { } while(0)
#define error_dev_va(x, ...) goto error
-#define debug_alt(x) while(0)
+#define debug_alt(x) do { } while(0)
#define error_alt(x) goto error
-#define debug_alt_va(x, ...) while(0)
+#define debug_alt_va(x, ...) do { } while(0)
#define error_alt_va(x, ...) goto error
#endif
@@ -119,9 +119,7 @@ static inline dnbd3_server_t *get_free_alt_server(dnbd3_device_t *const dev)
int dnbd3_net_connect(dnbd3_device_t *dev)
{
- struct sockaddr_in sin;
struct request *req1 = NULL;
-
struct timeval timeout;
char get_servers = 0, set_client = 0;
@@ -155,10 +153,10 @@ int dnbd3_net_connect(dnbd3_device_t *dev)
if (dev->sock)
error_dev("ERROR: Already connected.");
- if (dev->cur_server.host.type != AF_INET)
- error_dev("ERROR: IPv6 not implemented.");
- else
- debug_dev("INFO: Connecting...");
+ if (dev->cur_server.host.type != AF_INET && dev->cur_server.host.type != AF_INET6)
+ error_dev_va("ERROR: Unknown address type %d", (int)dev->cur_server.host.type);
+
+ debug_dev("INFO: Connecting...");
if (dev->better_sock == NULL)
{
@@ -171,16 +169,33 @@ int dnbd3_net_connect(dnbd3_device_t *dev)
char *name;
int mlen;
init_msghdr(msg);
- if (sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &dev->sock) < 0)
- error_dev("ERROR: Couldn't create socket.");
+
+ if (sock_create_kern(dev->cur_server.host.type, SOCK_STREAM, IPPROTO_TCP, &dev->sock) < 0)
+ error_dev("ERROR: Couldn't create socket (v6).");
+
kernel_setsockopt(dev->sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, sizeof(timeout));
kernel_setsockopt(dev->sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof(timeout));
dev->sock->sk->sk_allocation = GFP_NOIO;
- sin.sin_family = AF_INET;
- memcpy(&(sin.sin_addr.s_addr), dev->cur_server.host.addr, 4);
- sin.sin_port = dev->cur_server.host.port;
- if (kernel_connect(dev->sock, (struct sockaddr *) &sin, sizeof(sin), 0) != 0)
- error_dev("FATAL: Connection to host failed.");
+ if (dev->cur_server.host.type == AF_INET)
+ {
+ struct sockaddr_in sin;
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ memcpy(&(sin.sin_addr), dev->cur_server.host.addr, 4);
+ sin.sin_port = dev->cur_server.host.port;
+ if (kernel_connect(dev->sock, (struct sockaddr *) &sin, sizeof(sin), 0) != 0)
+ error_dev("FATAL: Connection to host failed. (v4)");
+ }
+ else
+ {
+ struct sockaddr_in6 sin;
+ memset(&sin, 0, sizeof(sin));
+ sin.sin6_family = AF_INET6;
+ memcpy(&(sin.sin6_addr), dev->cur_server.host.addr, 16);
+ sin.sin6_port = dev->cur_server.host.port;
+ if (kernel_connect(dev->sock, (struct sockaddr *) &sin, sizeof(sin), 0) != 0)
+ error_dev("FATAL: Connection to host failed. (v6)");
+ }
// Request filesize
dnbd3_request.magic = dnbd3_packet_magic;
dnbd3_request.cmd = CMD_SELECT_IMAGE;
@@ -395,7 +410,8 @@ void dnbd3_net_heartbeat(unsigned long arg)
int dnbd3_net_discover(void *data)
{
dnbd3_device_t *dev = data;
- struct sockaddr_in sin;
+ struct sockaddr_in sin4;
+ struct sockaddr_in6 sin6;
struct socket *sock, *best_sock = NULL;
dnbd3_request_t dnbd3_request;
@@ -421,6 +437,9 @@ int dnbd3_net_discover(void *data)
timeout.tv_sec = SOCKET_TIMEOUT_CLIENT_DISCOVERY;
timeout.tv_usec = 0;
+ memset(&sin4, 0, sizeof(sin4));
+ memset(&sin6, 0, sizeof(sin6));
+
init_msghdr(msg);
buf = kmalloc(4096, GFP_KERNEL);
@@ -454,7 +473,7 @@ int dnbd3_net_discover(void *data)
spin_lock_irqsave(&dev->blk_lock, irqflags);
for (i = 0; i < dev->new_servers_num; ++i)
{
- if (dev->new_servers[i].host.type != AF_INET) // Invalid entry.. (Add IPv6 someday)
+ if (dev->new_servers[i].host.type != AF_INET && dev->new_servers[i].host.type != AF_INET6) // Invalid entry?
continue;
alt_server = get_existing_server(&dev->new_servers[i], dev);
if (alt_server != NULL) // Server already known
@@ -462,8 +481,11 @@ int dnbd3_net_discover(void *data)
if (dev->new_servers[i].failures == 1)
{
// REMOVE request
+ if (alt_server->host.type == AF_INET)
+ debug_dev_va("Removing alt server %pI4", alt_server->host.addr);
+ else
+ debug_dev_va("Removing alt server %pI6", alt_server->host.addr);
alt_server->host.type = 0;
- debug_dev_va("Removing alt server %pI4", alt_server->host.addr);
continue;
}
// ADD, so just reset fail counter
@@ -477,7 +499,10 @@ int dnbd3_net_discover(void *data)
continue;
// Add new server entry
alt_server->host = dev->new_servers[i].host;
- debug_dev_va("Adding alt server %pI4", alt_server->host.addr);
+ if (alt_server->host.type == AF_INET)
+ debug_dev_va("Adding alt server %pI4", alt_server->host.addr);
+ else
+ debug_dev_va("Adding alt server %pI6", alt_server->host.addr);
alt_server->rtts[0] = alt_server->rtts[1]
= alt_server->rtts[2] = alt_server->rtts[3]
= RTT_UNREACHABLE;
@@ -499,7 +524,7 @@ int dnbd3_net_discover(void *data)
continue;
// Initialize socket and connect
- if (sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &sock) < 0)
+ if (sock_create_kern(dev->alt_servers[i].host.type, SOCK_STREAM, IPPROTO_TCP, &sock) < 0)
{
debug_alt("ERROR: Couldn't create socket (discover).");
sock = NULL;
@@ -508,11 +533,22 @@ int dnbd3_net_discover(void *data)
kernel_setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, sizeof(timeout));
kernel_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof(timeout));
sock->sk->sk_allocation = GFP_NOIO;
- sin.sin_family = AF_INET; // add IPv6.....
- memcpy(&sin.sin_addr.s_addr, dev->alt_servers[i].host.addr, 4);
- sin.sin_port = dev->alt_servers[i].host.port;
- if (kernel_connect(sock, (struct sockaddr *) &sin, sizeof(sin), 0) < 0)
- goto error;
+ if (dev->alt_servers[i].host.type == AF_INET)
+ {
+ sin4.sin_family = AF_INET;
+ memcpy(&sin4.sin_addr, dev->alt_servers[i].host.addr, 4);
+ sin4.sin_port = dev->alt_servers[i].host.port;
+ if (kernel_connect(sock, (struct sockaddr *) &sin4, sizeof(sin4), 0) < 0)
+ goto error;
+ }
+ else
+ {
+ sin6.sin6_family = AF_INET6;
+ memcpy(&sin6.sin6_addr, dev->alt_servers[i].host.addr, 16);
+ sin6.sin6_port = dev->alt_servers[i].host.port;
+ if (kernel_connect(sock, (struct sockaddr *) &sin6, sizeof(sin6), 0) < 0)
+ goto error;
+ }
// Request filesize
dnbd3_request.cmd = CMD_SELECT_IMAGE;
diff --git a/src/server/saveload.c b/src/server/saveload.c
index c3b0ff3..e888f50 100644
--- a/src/server/saveload.c
+++ b/src/server/saveload.c
@@ -36,7 +36,6 @@
static GKeyFile *_config_handle = NULL;
static dnbd3_image_t *prepare_image(char *image_name, int rid, char *image_file, char *cache_file);
-//static char* get_local_image_name(char *global_name);
void dnbd3_load_config()