summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsr2012-09-03 21:00:26 +0200
committersr2012-09-03 21:00:26 +0200
commit60b2ba6ef9ed779d750958b6422f05c93a4a2d91 (patch)
tree46fdacf6a9439947e91af4c3d9de3006d41e5380
parent[*] Fixed and unified formatting (diff)
downloaddnbd3-60b2ba6ef9ed779d750958b6422f05c93a4a2d91.tar.gz
dnbd3-60b2ba6ef9ed779d750958b6422f05c93a4a2d91.tar.xz
dnbd3-60b2ba6ef9ed779d750958b6422f05c93a4a2d91.zip
[SERVER] Check which dnbd3 devices are idle and ready to use for proxy mode
[SERVER] Skeleton of server-to-server communication [SERVER] Update access-time of images in use by actual clients [*] Add dnbd3_host_t type to handle address+port+addrtype consistently across the project
-rw-r--r--src/client/client.c18
-rw-r--r--src/kernel/blk.c14
-rw-r--r--src/kernel/dnbd3.h4
-rw-r--r--src/kernel/net.c78
-rw-r--r--src/kernel/sysfs.c22
-rw-r--r--src/server/helper.c162
-rw-r--r--src/server/helper.h30
-rw-r--r--src/server/ipc.c126
-rw-r--r--src/server/ipc.h2
-rw-r--r--src/server/job.c113
-rw-r--r--src/server/net.c4
-rw-r--r--src/server/saveload.c (renamed from src/server/utils.c)200
-rw-r--r--src/server/saveload.h (renamed from src/server/utils.h)4
-rw-r--r--src/server/server.c11
-rw-r--r--src/server/server.h41
-rw-r--r--src/server/xmlutil.h12
-rw-r--r--src/types.h19
17 files changed, 511 insertions, 349 deletions
diff --git a/src/client/client.c b/src/client/client.c
index b94076f..397ac38 100644
--- a/src/client/client.c
+++ b/src/client/client.c
@@ -93,8 +93,8 @@ int main(int argc, char *argv[])
memset(&msg, 0, sizeof(dnbd3_ioctl_t));
msg.len = (uint16_t)sizeof(dnbd3_ioctl_t);
msg.read_ahead_kb = DEFAULT_READ_AHEAD_KB;
- msg.port = htons(PORT);
- msg.addrtype = 0;
+ msg.host.port = htons(PORT);
+ msg.host.type = 0;
msg.imgname = NULL;
msg.is_server = FALSE;
@@ -125,8 +125,8 @@ int main(int argc, char *argv[])
_config_file_name = strdup(optarg);
break;
case 'h':
- dnbd3_get_ip(optarg, msg.addr, &msg.addrtype);
- printf("Host set to %s (type %d)\n", inet_ntoa(*(struct in_addr *)msg.addr), (int)msg.addrtype);
+ 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);
break;
case 'i':
msg.imgname = strdup(optarg);
@@ -147,7 +147,7 @@ int main(int argc, char *argv[])
close_dev = 1;
break;
case 's':
- dnbd3_get_ip(optarg, msg.addr, &msg.addrtype);
+ dnbd3_get_ip(optarg, msg.host.addr, &msg.host.type);
switch_host = 1;
break;
case 'H':
@@ -164,7 +164,7 @@ int main(int argc, char *argv[])
}
// close device
- if (close_dev && msg.addrtype == 0 && dev && (msg.imgname == NULL))
+ if (close_dev && msg.host.type == 0 && dev && (msg.imgname == NULL))
{
fd = open(dev, O_WRONLY);
printf("INFO: Closing device %s\n", dev);
@@ -181,7 +181,7 @@ int main(int argc, char *argv[])
}
// switch host
- if (switch_host && msg.addrtype != 0 && dev && (msg.imgname == NULL))
+ if (switch_host && msg.host.type != 0 && dev && (msg.imgname == NULL))
{
fd = open(dev, O_WRONLY);
printf("INFO: Switching device %s to %s\n", dev, "<fixme>");
@@ -198,7 +198,7 @@ int main(int argc, char *argv[])
}
// connect
- if (msg.addrtype != 0 && dev && (msg.imgname != NULL))
+ if (msg.host.type != 0 && dev && (msg.imgname != NULL))
{
msg.imgnamelen = (uint16_t)strlen(msg.imgname);
fd = open(dev, O_WRONLY);
@@ -229,7 +229,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.addr, &msg.addrtype);
+ dnbd3_get_ip(g_key_file_get_string(gkf, groups[i], "server", NULL), msg.host.addr, &msg.host.type);
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/blk.c b/src/kernel/blk.c
index bc138c3..4282295 100644
--- a/src/kernel/blk.c
+++ b/src/kernel/blk.c
@@ -140,9 +140,9 @@ int dnbd3_blk_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, u
}
else
{
- memcpy(dev->cur_server.hostaddr, msg->addr, 16);
- dev->cur_server.port = msg->port;
- dev->cur_server.hostaddrtype = msg->addrtype;
+ if (sizeof(msg->host) != sizeof(dev->cur_server.host))
+ printk("Odd size bug#1 triggered in IOCTL\n");
+ memcpy(&dev->cur_server.host, &msg->host, sizeof(msg->host));
dev->cur_server.failures = 0;
memcpy(&dev->initial_server, &dev->cur_server, sizeof(dev->initial_server));
dev->imgname = imgname;
@@ -176,9 +176,7 @@ int dnbd3_blk_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, u
case IOCTL_SWITCH:
dnbd3_net_disconnect(dev);
- memcpy(dev->cur_server.hostaddr, msg->addr, 16);
- dev->cur_server.port = msg->port;
- dev->cur_server.hostaddrtype = msg->addrtype;
+ memcpy(&dev->cur_server.host, &msg->host, sizeof(msg->host));
result = dnbd3_net_connect(dev);
break;
@@ -195,9 +193,7 @@ int dnbd3_blk_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, u
result = -EAGAIN;
else
{
- memcpy(dev->new_servers[dev->new_servers_num].hostaddr, msg->addr, 16);
- dev->new_servers[dev->new_servers_num].port = msg->port;
- dev->new_servers[dev->new_servers_num].hostaddrtype = msg->addrtype;
+ memcpy(&dev->new_servers[dev->new_servers_num].host, &msg->host, sizeof(msg->host));
dev->new_servers[dev->new_servers_num].failures = (cmd == IOCTL_ADD_SRV ? 0 : 1); // 0 = ADD, 1 = REM
++dev->new_servers_num;
result = 0;
diff --git a/src/kernel/dnbd3.h b/src/kernel/dnbd3.h
index fb83575..e7911cf 100644
--- a/src/kernel/dnbd3.h
+++ b/src/kernel/dnbd3.h
@@ -35,11 +35,9 @@ extern int major;
typedef struct
{
+ dnbd3_host_t host;
unsigned long rtts[4]; // Last four round trip time measurements in µs
- uint16_t port; // Port in network representation
uint16_t protocol_version; // dnbd3 protocol version of this server
- uint8_t hostaddr[16]; // Address in network representation (IPv4 or IPv6)
- uint8_t hostaddrtype; // Address type (AF_INET or AF_INET6)
uint8_t failures; // How many times the server was unreachable
} dnbd3_server_t;
diff --git a/src/kernel/net.c b/src/kernel/net.c
index 2cd3cac..f437464 100644
--- a/src/kernel/net.c
+++ b/src/kernel/net.c
@@ -36,34 +36,34 @@
*/
#if 1 // Change to 0 to disable debug messages
#define debug_print_va_host(_host, _fmt, ...) do { \
- if (dev->cur_server.hostaddrtype == AF_INET) \
- printk("%s:%d " _fmt " (%s, %pI4:%d)\n", __FILE__, __LINE__, __VA_ARGS__, dev->disk->disk_name, (_host).hostaddr, (int)ntohs((_host).port)); \
+ if ((_host).type == AF_INET) \
+ printk("%s:%d " _fmt " (%s, %pI4:%d)\n", __FILE__, __LINE__, __VA_ARGS__, dev->disk->disk_name, (_host).addr, (int)ntohs((_host).port)); \
else \
- printk("%s:%d " _fmt " (%s, [%pI6]:%d)\n", __FILE__, __LINE__, __VA_ARGS__, dev->disk->disk_name, (_host).hostaddr, (int)ntohs((_host).port)); \
+ printk("%s:%d " _fmt " (%s, [%pI6]:%d)\n", __FILE__, __LINE__, __VA_ARGS__, dev->disk->disk_name, (_host).addr, (int)ntohs((_host).port)); \
} while(0)
#define debug_error_va_host(_host, _fmt, ...) do { \
debug_print_va_host(_host, _fmt, __VA_ARGS__); \
goto error; \
} while(0)
-#define debug_dev_va(_fmt, ...) debug_print_va_host(dev->cur_server, _fmt, __VA_ARGS__)
-#define error_dev_va(_fmt, ...) debug_error_va_host(dev->cur_server, _fmt, __VA_ARGS__)
-#define debug_alt_va(_fmt, ...) debug_print_va_host(dev->alt_servers[i], _fmt, __VA_ARGS__)
-#define error_alt_va(_fmt, ...) debug_error_va_host(dev->alt_servers[i], _fmt, __VA_ARGS__)
+#define debug_dev_va(_fmt, ...) debug_print_va_host(dev->cur_server.host, _fmt, __VA_ARGS__)
+#define error_dev_va(_fmt, ...) debug_error_va_host(dev->cur_server.host, _fmt, __VA_ARGS__)
+#define debug_alt_va(_fmt, ...) debug_print_va_host(dev->alt_servers[i].host, _fmt, __VA_ARGS__)
+#define error_alt_va(_fmt, ...) debug_error_va_host(dev->alt_servers[i].host, _fmt, __VA_ARGS__)
#define debug_print_host(_host, txt) do { \
- if (dev->cur_server.hostaddrtype == AF_INET) \
- printk("%s:%d " txt " (%s, %pI4:%d)\n", __FILE__, __LINE__, dev->disk->disk_name, (_host).hostaddr, (int)ntohs((_host).port)); \
+ if ((_host).type == AF_INET) \
+ printk("%s:%d " txt " (%s, %pI4:%d)\n", __FILE__, __LINE__, dev->disk->disk_name, (_host).addr, (int)ntohs((_host).port)); \
else \
- printk("%s:%d " txt " (%s, [%pI6]:%d)\n", __FILE__, __LINE__, dev->disk->disk_name, (_host).hostaddr, (int)ntohs((_host).port)); \
+ printk("%s:%d " txt " (%s, [%pI6]:%d)\n", __FILE__, __LINE__, dev->disk->disk_name, (_host).addr, (int)ntohs((_host).port)); \
} while(0)
#define debug_error_host(_host, txt) do { \
debug_print_host(_host, txt); \
goto error; \
} while(0)
-#define debug_dev(txt) debug_print_host(dev->cur_server, txt)
-#define error_dev(txt) debug_error_host(dev->cur_server, txt)
-#define debug_alt(txt) debug_print_host(dev->alt_servers[i], txt)
-#define error_alt(txt) debug_error_host(dev->alt_servers[i], txt)
+#define debug_dev(txt) debug_print_host(dev->cur_server.host, txt)
+#define error_dev(txt) debug_error_host(dev->cur_server.host, txt)
+#define debug_alt(txt) debug_print_host(dev->alt_servers[i].host, txt)
+#define error_alt(txt) debug_error_host(dev->alt_servers[i].host, txt)
#else // Silent
@@ -79,9 +79,9 @@
static inline int is_same_server(const dnbd3_server_t *const a, const dnbd3_server_t *const b)
{
- return (a->hostaddrtype == b->hostaddrtype)
- && (a->port == b->port)
- && (0 == memcmp(a->hostaddr, b->hostaddr, (a->hostaddrtype == AF_INET ? 4 : 16)));
+ return (a->host.type == b->host.type)
+ && (a->host.port == b->host.port)
+ && (0 == memcmp(a->host.addr, b->host.addr, (a->host.type == AF_INET ? 4 : 16)));
}
static inline dnbd3_server_t *get_existing_server(const dnbd3_server_entry_t *const newserver, dnbd3_device_t *const dev)
@@ -89,9 +89,9 @@ static inline dnbd3_server_t *get_existing_server(const dnbd3_server_entry_t *co
int i;
for (i = 0; i < NUMBER_SERVERS; ++i)
{
- if ((newserver->hostaddrtype == dev->alt_servers[i].hostaddrtype)
- && (newserver->port == dev->alt_servers[i].port)
- && (0 == memcmp(newserver->hostaddr, dev->alt_servers[i].hostaddr, (newserver->hostaddrtype == AF_INET ? 4 : 16))))
+ if ((newserver->host.type == dev->alt_servers[i].host.type)
+ && (newserver->host.port == dev->alt_servers[i].host.port)
+ && (0 == memcmp(newserver->host.addr, dev->alt_servers[i].host.addr, (newserver->host.type == AF_INET ? 4 : 16))))
{
return &dev->alt_servers[i];
break;
@@ -105,7 +105,7 @@ static inline dnbd3_server_t *get_free_alt_server(dnbd3_device_t *const dev)
int i;
for (i = 0; i < NUMBER_SERVERS; ++i)
{
- if (dev->alt_servers[i].hostaddrtype == 0)
+ if (dev->alt_servers[i].host.type == 0)
return &dev->alt_servers[i];
}
for (i = 0; i < NUMBER_SERVERS; ++i)
@@ -153,12 +153,12 @@ int dnbd3_net_connect(dnbd3_device_t *dev)
error_dev("FATAL: Kmalloc(1) failed.");
}
- if (dev->cur_server.port == 0 || dev->cur_server.hostaddrtype == 0 || dev->imgname == NULL)
+ if (dev->cur_server.host.port == 0 || dev->cur_server.host.type == 0 || dev->imgname == NULL)
error_dev("FATAL: Host, port or image name not set.");
if (dev->sock)
error_dev("ERROR: Already connected.");
- if (dev->cur_server.hostaddrtype != AF_INET)
+ if (dev->cur_server.host.type != AF_INET)
error_dev("ERROR: IPv6 not implemented.");
else
debug_dev("INFO: Connecting...");
@@ -180,8 +180,8 @@ int dnbd3_net_connect(dnbd3_device_t *dev)
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.hostaddr, 4);
- sin.sin_port = dev->cur_server.port;
+ 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.");
// Request filesize
@@ -291,8 +291,8 @@ error:
sock_release(dev->sock);
dev->sock = NULL;
}
- dev->cur_server.hostaddrtype = 0;
- dev->cur_server.port = 0;
+ dev->cur_server.host.type = 0;
+ dev->cur_server.host.port = 0;
if (req1) kfree(req1);
return -1;
}
@@ -337,8 +337,8 @@ int dnbd3_net_disconnect(dnbd3_device_t *dev)
sock_release(dev->sock);
dev->sock = NULL;
}
- dev->cur_server.hostaddrtype = 0;
- dev->cur_server.port = 0;
+ dev->cur_server.host.type = 0;
+ dev->cur_server.host.port = 0;
dev->disconnecting = 0;
@@ -451,7 +451,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].hostaddrtype != AF_INET) // Invalid entry.. (Add IPv6)
+ if (dev->new_servers[i].host.type != AF_INET) // Invalid entry.. (Add IPv6)
continue;
alt_server = get_existing_server(&dev->new_servers[i], dev);
if (alt_server != NULL) // Server already known
@@ -459,7 +459,7 @@ int dnbd3_net_discover(void *data)
if (dev->new_servers[i].failures == 1)
{
// REMOVE request
- alt_server->hostaddrtype = 0;
+ alt_server->host.type = 0;
continue;
}
// ADD, so just reset fail counter
@@ -472,9 +472,9 @@ int dnbd3_net_discover(void *data)
if (alt_server == NULL) // All NUMBER_SERVERS slots are taken, ignore entry
continue;
// Add new server entry
- memcpy(alt_server->hostaddr, dev->new_servers[i].hostaddr, 16);
- alt_server->hostaddrtype = dev->new_servers[i].hostaddrtype;
- alt_server->port = dev->new_servers[i].port;
+ memcpy(alt_server->host.addr, dev->new_servers[i].host.addr, 16);
+ alt_server->host.type = dev->new_servers[i].host.type;
+ alt_server->host.port = dev->new_servers[i].host.port;
alt_server->rtts[0] = alt_server->rtts[1]
= alt_server->rtts[2] = alt_server->rtts[3]
= RTT_UNREACHABLE;
@@ -490,7 +490,7 @@ int dnbd3_net_discover(void *data)
for (i=0; i < NUMBER_SERVERS; ++i)
{
- if (dev->alt_servers[i].hostaddrtype == 0) // Empty slot
+ if (dev->alt_servers[i].host.type == 0) // Empty slot
continue;
if (!dev->panic && dev->alt_servers[i].failures > 50) // If not in panic mode, skip server if it failed too many times
continue;
@@ -506,8 +506,8 @@ int dnbd3_net_discover(void *data)
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].hostaddr, 4);
- sin.sin_port = dev->alt_servers[i].port;
+ 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;
@@ -565,7 +565,7 @@ int dnbd3_net_discover(void *data)
// panic mode, take first responding server
if (dev->panic)
{
- printk("WARN: Panic mode (%s), taking server %pI4 : %d\n", dev->disk->disk_name, dev->alt_servers[i].hostaddr, (int)ntohs(dev->alt_servers[i].port));
+ debug_alt("WARN: Panic mode, changing server:");
if (best_sock != NULL) sock_release(best_sock);
dev->better_sock = sock; // Pass over socket to take a shortcut in *_connect();
kfree(buf);
@@ -796,7 +796,7 @@ int dnbd3_net_send(void *data)
return 0;
error:
- printk("ERROR: Connection to server %pI4 : %d lost (send)\n", dev->cur_server.hostaddr, (int)ntohs(dev->cur_server.port));
+ debug_dev("ERROR: Connection to server lost (send)");
if (dev->sock)
kernel_sock_shutdown(dev->sock, SHUT_RDWR);
dev->thread_send = NULL;
diff --git a/src/kernel/sysfs.c b/src/kernel/sysfs.c
index 596e745..d219c86 100644
--- a/src/kernel/sysfs.c
+++ b/src/kernel/sysfs.c
@@ -29,10 +29,10 @@
ssize_t show_cur_server_addr(char *buf, dnbd3_device_t *dev)
{
- if (dev->cur_server.hostaddrtype == AF_INET)
- return MIN(snprintf(buf, PAGE_SIZE, "%pI4,%d\n", dev->cur_server.hostaddr, (int)ntohs(dev->cur_server.port)), PAGE_SIZE);
- else if (dev->cur_server.hostaddrtype == AF_INET6)
- return MIN(snprintf(buf, PAGE_SIZE, "%pI6,%d\n", dev->cur_server.hostaddr, (int)ntohs(dev->cur_server.port)), PAGE_SIZE);
+ if (dev->cur_server.host.type == AF_INET)
+ return MIN(snprintf(buf, PAGE_SIZE, "%pI4,%d\n", dev->cur_server.host.addr, (int)ntohs(dev->cur_server.host.port)), PAGE_SIZE);
+ else if (dev->cur_server.host.type == AF_INET6)
+ return MIN(snprintf(buf, PAGE_SIZE, "%pI6,%d\n", dev->cur_server.host.addr, (int)ntohs(dev->cur_server.host.port)), PAGE_SIZE);
*buf = '\0';
return 0;
}
@@ -47,7 +47,7 @@ ssize_t show_alt_server_num(char *buf, dnbd3_device_t *dev)
int i, num = 0;
for (i = 0; i < NUMBER_SERVERS; ++i)
{
- if (dev->alt_servers[i].hostaddrtype) ++num;
+ if (dev->alt_servers[i].host.type) ++num;
}
return MIN(snprintf(buf, PAGE_SIZE, "%d\n", num), PAGE_SIZE);
}
@@ -57,17 +57,17 @@ ssize_t show_alt_servers(char *buf, dnbd3_device_t *dev)
int i, size = PAGE_SIZE, ret;
for (i = 0; i < NUMBER_SERVERS; ++i)
{
- if (dev->alt_servers[i].hostaddrtype == AF_INET)
+ if (dev->alt_servers[i].host.type == AF_INET)
ret = MIN(snprintf(buf, size, "%pI4,%d,%llu,%d\n",
- dev->alt_servers[i].hostaddr,
- (int)ntohs(dev->alt_servers[i].port),
+ dev->alt_servers[i].host.addr,
+ (int)ntohs(dev->alt_servers[i].host.port),
(unsigned long long)((dev->alt_servers[i].rtts[0] + dev->alt_servers[i].rtts[1] + dev->alt_servers[i].rtts[2] + dev->alt_servers[i].rtts[3]) / 4),
(int)dev->alt_servers[i].failures)
, size);
- else if (dev->alt_servers[i].hostaddrtype == AF_INET6)
+ else if (dev->alt_servers[i].host.type == AF_INET6)
ret = MIN(snprintf(buf, size, "%pI6,%d,%llu,%d\n",
- dev->alt_servers[i].hostaddr,
- (int)ntohs(dev->alt_servers[i].port),
+ dev->alt_servers[i].host.addr,
+ (int)ntohs(dev->alt_servers[i].host.port),
(unsigned long long)((dev->alt_servers[i].rtts[0] + dev->alt_servers[i].rtts[1] + dev->alt_servers[i].rtts[2] + dev->alt_servers[i].rtts[3]) / 4),
(int)dev->alt_servers[i].failures)
, size);
diff --git a/src/server/helper.c b/src/server/helper.c
new file mode 100644
index 0000000..293fa36
--- /dev/null
+++ b/src/server/helper.c
@@ -0,0 +1,162 @@
+#include "helper.h"
+#include <arpa/inet.h>
+#include <string.h>
+#include <stdlib.h>
+#include <glib/gmacros.h>
+#include "../config.h"
+
+/**
+ * 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 !!
+ */
+char parse_address(char *string, dnbd3_host_t *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;
+}
+
+/**
+ * Convert a host and port (network byte order) to printable representation.
+ * Worst case required buffer len is 48, eg. [1234:1234:1234:1234:1234:1234:1234:1234]:12345 (+ \0)
+ * Returns TRUE on success, FALSE on error
+ */
+char host_to_string(const dnbd3_host_t *host, char *target, size_t targetlen)
+{
+ // Worst case: Port 5 chars, ':' to separate ip and port 1 char, terminating null 1 char = 7, [] for IPv6
+ if (targetlen < 10)
+ return FALSE;
+ if (host->type == AF_INET6)
+ {
+ *target++ = '[';
+ inet_ntop(AF_INET6, host->addr, target, targetlen - 9);
+ target += strlen(target);
+ *target++ = ']';
+ }
+ else if (host->type == AF_INET)
+ {
+ inet_ntop(AF_INET, host->addr, target, targetlen - 7);
+ target += strlen(target);
+ }
+ else
+ {
+ snprintf(target, targetlen, "<?addrtype=%d>", (int)host->type);
+ return FALSE;
+ }
+ *target = '\0';
+ if (host->port != 0)
+ {
+ // There are still at least 7 bytes left in the buffer, port is at most 5 bytes + ':' + '\0' = 7
+ snprintf(target, 7, ":%d", (int)ntohs(host->port));
+ }
+ return TRUE;
+}
+
+char is_valid_namespace(char *namespace)
+{
+ if (*namespace == '\0' || *namespace == '/')
+ return 0; // Invalid: Length = 0 or starting with a slash
+ while (*namespace)
+ {
+ if (*namespace != '/' && *namespace != '-' && (*namespace < 'a' || *namespace > 'z')
+ && (*namespace < 'A' || *namespace > 'Z')
+ && (*namespace < '0' || *namespace > '9'))
+ return 0;
+ ++namespace;
+ }
+ if (strstr(namespace, "//") != NULL)
+ return 0; // Invalid: Double slash
+ if (*(namespace - 1) == '/')
+ return 0; // Invalid: Ends in a slash
+ return 1;
+}
+
+char is_valid_imagename(char *namespace)
+{
+ if (*namespace == '\0' || *namespace == ' ')
+ return 0; // Invalid: Length = 0 or starting with a space
+ while (*namespace)
+ {
+ // Check for invalid chars
+ if (*namespace != '.' && *namespace != '-' && *namespace != ' '
+ && *namespace != '(' && *namespace != ')'
+ && (*namespace < 'a' || *namespace > 'z') && (*namespace < 'A' || *namespace > 'Z')
+ && (*namespace < '0' || *namespace > '9'))
+ return 0;
+ ++namespace;
+ }
+ if (*(namespace - 1) == ' ')
+ return 0; // Invalid: Ends in a space
+ return 1;
+}
+
+void strtolower(char *string)
+{
+ while (*string)
+ {
+ if (*string >= 'A' && *string <= 'Z')
+ *string += 32;
+ ++string;
+ }
+}
diff --git a/src/server/helper.h b/src/server/helper.h
new file mode 100644
index 0000000..e787c42
--- /dev/null
+++ b/src/server/helper.h
@@ -0,0 +1,30 @@
+#ifndef HELPER_H_
+#define HELPER_H_
+
+#include "server.h"
+#include <netinet/in.h>
+#include <string.h>
+
+char parse_address(char *string, dnbd3_host_t *host);
+char host_to_string(const dnbd3_host_t *host, char *target, size_t targetlen);
+char is_valid_namespace(char *namespace);
+char is_valid_imagename(char *namespace);
+void strtolower(char *string);
+
+static inline int is_same_server(const dnbd3_trusted_server_t *const a, const dnbd3_trusted_server_t *const b)
+{
+ return (a->host.type == b->host.type)
+ && (a->host.port == b->host.port)
+ && (0 == memcmp(a->host.addr, b->host.addr, (a->host.type == AF_INET ? 4 : 16)));
+}
+
+// one byte in the map covers 8 4kib blocks, so 32kib per byte
+// "+ (1 << 15) - 1" is required to account for the last bit of
+// the image that is smaller than 32kib
+// this would be the case whenever the image file size is not a
+// multiple of 32kib (= the number of blocks is not divisible by 8)
+// ie: if the image is 49152 bytes and you do 49152 >> 15 you get 1,
+// but you actually need 2 bytes to have a complete cache map
+#define IMGSIZE_TO_MAPBYTES(bytes) ((int)(((bytes) + (1 << 15) - 1) >> 15))
+
+#endif
diff --git a/src/server/ipc.c b/src/server/ipc.c
index 339dcc6..b93844a 100644
--- a/src/server/ipc.c
+++ b/src/server/ipc.c
@@ -18,6 +18,13 @@
*
*/
+#include "ipc.h"
+#include "../config.h"
+#include "server.h"
+#include "saveload.h"
+#include "memlog.h"
+#include "helper.h"
+
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
@@ -37,12 +44,6 @@
#include <libxml/xpath.h>
#include "xmlutil.h"
-#include "ipc.h"
-#include "../config.h"
-#include "server.h"
-#include "utils.h"
-#include "memlog.h"
-
#define IPC_PORT (PORT+1)
static int server_sock = -1;
@@ -363,7 +364,6 @@ static int ipc_receive(int client_sock)
{
GSList *iterator, *iterator2;
- struct tm *timeinfo;
#define STRBUFLEN 100
char strbuffer[STRBUFLEN];
@@ -433,8 +433,7 @@ static int ipc_receive(int client_sock)
if (tmp_node == NULL)
goto get_info_reply_cleanup;
xmlNewProp(tmp_node, BAD_CAST "name", BAD_CAST image->config_group);
- timeinfo = localtime(&image->atime);
- strftime(strbuffer, STRBUFLEN, "%d.%m.%y %H:%M:%S", timeinfo);
+ sprintf(strbuffer, "%u", (unsigned int)image->atime);
xmlNewProp(tmp_node, BAD_CAST "atime", BAD_CAST strbuffer);
sprintf(strbuffer, "%d", image->rid);
xmlNewProp(tmp_node, BAD_CAST "rid", BAD_CAST strbuffer);
@@ -471,7 +470,7 @@ static int ipc_receive(int client_sock)
if (tmp_node == NULL)
goto get_info_reply_cleanup;
*strbuffer = '\0';
- inet_ntop(client->addrtype, client->ipaddr, strbuffer, STRBUFLEN);
+ host_to_string(&client->host, strbuffer, STRBUFLEN);
xmlNewProp(tmp_node, BAD_CAST "ip", BAD_CAST strbuffer);
xmlNewProp(tmp_node, BAD_CAST "file", BAD_CAST client->image->file);
xmlAddChild(parent_node, tmp_node);
@@ -490,15 +489,14 @@ static int ipc_receive(int client_sock)
for (iterator = _trusted_servers; iterator; iterator = iterator->next)
{
dnbd3_trusted_server_t *server = iterator->data;
- if (server->hostaddrtype != 0)
+ if (server->host.type != 0)
{
tmp_node = xmlNewNode(NULL, BAD_CAST "server");
if (tmp_node == NULL)
goto get_info_reply_cleanup;
- *strbuffer = '\0';
- inet_ntop(server->hostaddrtype, server->hostaddr, strbuffer, STRBUFLEN);
+ host_to_string(&server->host, strbuffer, STRBUFLEN);
xmlNewProp(tmp_node, BAD_CAST "ip", BAD_CAST strbuffer);
- sprintf(strbuffer, "%d", (int)server->port);
+ sprintf(strbuffer, "%d", (int)server->host.port);
xmlNewProp(tmp_node, BAD_CAST "port", BAD_CAST strbuffer);
if (server->comment)
xmlNewProp(tmp_node, BAD_CAST "comment", BAD_CAST server->comment);
@@ -576,32 +574,28 @@ get_info_reply_cleanup:
FOR_EACH_NODE(docRequest, "/data/images/image", cur)
{
- if (cur->type == XML_ELEMENT_NODE)
+ if (cur->type != XML_ELEMENT_NODE)
+ continue;
+ NEW_POINTERLIST;
+ ++count;
+ dnbd3_image_t image;
+ memset(&image, 0, sizeof(dnbd3_image_t));
+ image.config_group = (char *)XML_GETPROP(cur, "name");
+ char *rid_str = (char *)XML_GETPROP(cur, "rid");
+ image.file = (char *)XML_GETPROP(cur, "file");
+ image.cache_file = (char *)XML_GETPROP(cur, "cache");
+ if (image.config_group && rid_str && image.file && image.cache_file)
{
- ++count;
- dnbd3_image_t image;
- memset(&image, 0, sizeof(dnbd3_image_t));
- image.config_group = (char *)xmlGetNoNsProp(cur, BAD_CAST "name");
- char *rid_str = (char *)xmlGetNoNsProp(cur, BAD_CAST "rid");
- image.file = (char *)xmlGetNoNsProp(cur, BAD_CAST "file");
- image.cache_file = (char *)xmlGetNoNsProp(cur, BAD_CAST "cache");
- if (image.config_group && rid_str && image.file && image.cache_file)
- {
- image.rid = atoi(rid_str);
- if (cmd == IPC_ADDIMG)
- header.error = htonl(dnbd3_add_image(&image));
- else
- header.error = htonl(dnbd3_del_image(&image));
- }
+ image.rid = atoi(rid_str);
+ if (cmd == IPC_ADDIMG)
+ header.error = htonl(dnbd3_add_image(&image));
else
- header.error = htonl(ERROR_MISSING_ARGUMENT);
- xmlFree(image.config_group);
- xmlFree(rid_str);
- xmlFree(image.file);
- xmlFree(image.cache_file);
+ header.error = htonl(dnbd3_del_image(&image));
}
- }
- END_FOR_EACH;
+ else
+ header.error = htonl(ERROR_MISSING_ARGUMENT);
+ FREE_POINTERLIST;
+ } END_FOR_EACH;
if (count == 0)
header.error = htonl(ERROR_MISSING_ARGUMENT);
}
@@ -712,22 +706,20 @@ void dnbd3_ipc_send(int cmd)
printf("--- Last log lines ----\n%s\n\n", log);
}
- int watime = 0, wname = 0, wrid = 5;
+ int watime = 17, wname = 0, wrid = 5;
FOR_EACH_NODE(doc, "/data/images/image", cur)
{
if (cur->type != XML_ELEMENT_NODE)
continue;
- xmlChar *atime = xmlGetNoNsProp(cur, BAD_CAST "atime");
- xmlChar *vid = xmlGetNoNsProp(cur, BAD_CAST "name");
- xmlChar *rid = xmlGetNoNsProp(cur, BAD_CAST "rid");
- watime = MAX(watime, xmlStrlen(atime));
+ NEW_POINTERLIST; // This macro defines an array of pointers
+ xmlChar *vid = XML_GETPROP(cur, "name"); // XML_GETPROP is a macro wrapping xmlGetNoNsProp()
+ xmlChar *rid = XML_GETPROP(cur, "rid"); // Each of these calls allocates memory for the string
wname = MAX(wname, xmlStrlen(vid));
wrid = MAX(wrid, xmlStrlen(rid));
- // Too lazy to free vars, client will exit anyways
- }
- END_FOR_EACH;
+ FREE_POINTERLIST; // This macro simply frees all pointers in the above array
+ } END_FOR_EACH;
- char format[100];
+ char format[100], strbuffer[STRBUFLEN];
snprintf(format, 100,
"%%-%ds %%-%ds %%%ds %%s\n", watime, wname, wrid);
@@ -740,15 +732,18 @@ void dnbd3_ipc_send(int cmd)
{
if (cur->type != XML_ELEMENT_NODE)
continue;
+ NEW_POINTERLIST;
++count;
- xmlChar *atime = xmlGetNoNsProp(cur, BAD_CAST "atime");
- xmlChar *vid = xmlGetNoNsProp(cur, BAD_CAST "name");
- xmlChar *rid = xmlGetNoNsProp(cur, BAD_CAST "rid");
- xmlChar *file = xmlGetNoNsProp(cur, BAD_CAST "file");
- printf(format, atime, vid, rid, file);
- // Too lazy to free vars, client will exit anyways
- }
- END_FOR_EACH;
+ xmlChar *numatime = XML_GETPROP(cur, "atime");
+ xmlChar *vid = XML_GETPROP(cur, "name");
+ xmlChar *rid = XML_GETPROP(cur, "rid");
+ xmlChar *file = XML_GETPROP(cur, "file");
+ time_t at = (time_t)atol((char*)numatime);
+ struct tm *timeinfo = localtime(&at);
+ strftime(strbuffer, STRBUFLEN, "%d.%m.%y %H:%M:%S", timeinfo);
+ printf(format, strbuffer, vid, rid, file);
+ FREE_POINTERLIST;
+ } END_FOR_EACH;
char_repeat_br('=', term_width);
printf("\nNumber of images: %d\n\n", count);
@@ -765,8 +760,7 @@ void dnbd3_ipc_send(int cmd)
xmlChar *file = xmlGetNoNsProp(cur, BAD_CAST "file");
printf("%-40s %s\n", ip, file);
// Too lazy to free vars, client will exit anyways
- }
- END_FOR_EACH;
+ } END_FOR_EACH;
char_repeat_br('=', term_width);
printf("\nNumber clients: %d\n\n", count);
@@ -778,30 +772,32 @@ void dnbd3_ipc_send(int cmd)
{
if (cur->type != XML_ELEMENT_NODE)
continue;
+ NEW_POINTERLIST;
++count;
- xmlChar *ip = xmlGetNoNsProp(cur, BAD_CAST "ip");
- xmlChar *comment = xmlGetNoNsProp(cur, BAD_CAST "comment");
+ xmlChar *ip = XML_GETPROP(cur, "ip");
+ xmlChar *comment = XML_GETPROP(cur, "comment");
if (comment)
printf("%-30s (%s)\n", ip, comment);
else
printf("%-30s\n", ip);
for (childit = cur->children; childit; childit = childit->next)
{
- if (childit->type != XML_ELEMENT_NODE || childit->name == NULL || strcmp(childit->name, "namespace") != 0)
+ if (childit->type != XML_ELEMENT_NODE || childit->name == NULL || strcmp((const char*)childit->name, "namespace") != 0)
continue;
- xmlChar *name = xmlGetNoNsProp(childit, BAD_CAST "name");
- xmlChar *replicate = xmlGetNoNsProp(childit, BAD_CAST "replicate");
- xmlChar *recursive = xmlGetNoNsProp(childit, BAD_CAST "recursive");
+ NEW_POINTERLIST;
+ xmlChar *name = XML_GETPROP(childit, "name");
+ xmlChar *replicate = XML_GETPROP(childit, "replicate");
+ xmlChar *recursive = XML_GETPROP(childit, "recursive");
printf(" %-40s ", name);
if (replicate && *replicate != '0')
printf(" replicate");
if (recursive && *recursive != '0')
printf(" recursive");
putchar('\n');
+ FREE_POINTERLIST;
}
- // Too lazy to free vars, client will exit anyways
- }
- END_FOR_EACH;
+ FREE_POINTERLIST;
+ } END_FOR_EACH;
char_repeat_br('=', term_width);
printf("\nNumber servers: %d\n\n", count);
diff --git a/src/server/ipc.h b/src/server/ipc.h
index 36d1f60..fb29efc 100644
--- a/src/server/ipc.h
+++ b/src/server/ipc.h
@@ -21,6 +21,8 @@
#ifndef IPC_H_
#define IPC_H_
+#include <stdint.h>
+
#define IPC_EXIT 0
#define IPC_RELOAD 1
#define IPC_INFO 2
diff --git a/src/server/job.c b/src/server/job.c
index 1f10cb6..4a30cd1 100644
--- a/src/server/job.c
+++ b/src/server/job.c
@@ -1,5 +1,7 @@
#include "job.h"
-#include "utils.h"
+#include "saveload.h"
+#include "memlog.h"
+
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -7,8 +9,15 @@
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
#include <glib/gslist.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include "xmlutil.h"
+
#define DEV_STRLEN 12 // INCLUDING NULLCHAR (increase to 13 if you need more than 100 (0-99) devices)
#define MAX_NUM_DEVICES_TO_CHECK 100
@@ -34,6 +43,7 @@ static char keep_running = TRUE;
// Private functions
static char *get_free_device();
static void query_servers();
+static void update_image_atimes(time_t now);
//
@@ -73,7 +83,8 @@ void *dnbd3_job_thread(void *data)
{
const time_t starttime = time(NULL);
//
- // TODO: Update image atime
+ // Update image atime
+ update_image_atimes(starttime);
// Call image deletion function if last call is more than 5 minutes ago
if (starttime < next_delete_invocation)
{
@@ -99,32 +110,116 @@ void dnbd3_job_shutdown()
keep_running = FALSE;
}
+static void update_image_atimes(time_t now)
+{
+ GSList *iterator;
+ pthread_spin_lock(&_spinlock);
+ for (iterator = _dnbd3_clients; iterator; iterator = iterator->next)
+ {
+ dnbd3_client_t *client = iterator->data;
+ if (client && client->image && !client->is_server)
+ client->image->atime = now;
+ }
+ pthread_spin_unlock(&_spinlock);
+}
+
static void query_servers()
{
- struct timeval client_timeout;
+ if (_trusted_servers == NULL)
+ return;
+ struct timeval client_timeout, connect_timeout;
client_timeout.tv_sec = 0;
client_timeout.tv_usec = 500 * 1000;
- int client_sock;
- // Apply read/write timeout
- setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, &client_timeout, sizeof(client_timeout));
- setsockopt(client_sock, SOL_SOCKET, SO_SNDTIMEO, &client_timeout, sizeof(client_timeout));
+ connect_timeout.tv_sec = 2;
+ connect_timeout.tv_usec = 0;
+ int client_sock, num;
+ dnbd3_trusted_server_t *server;
+ dnbd3_host_t host;
+ struct sockaddr_in addr4;
+ for (num = 0;; ++num)
+ {
+ // "Iterate" this way to prevent holding the lock for a long time, although it is possible to skip a server this way...
+ pthread_spin_lock(&_spinlock);
+ server = g_slist_nth_data(_trusted_servers, num);
+ if (server == NULL)
+ {
+ pthread_spin_unlock(&_spinlock);
+ break; // Done
+ }
+ memcpy(&host, &server->host, sizeof(host));
+ pthread_spin_unlock(&_spinlock);
+ // Connect
+ if (host.type != AF_INET)
+ {
+ printf("[DEBUG] Unsupported addr type '%d', ignoring trusted server.\n", (int)host.type);
+ continue;
+ }
+ // Create socket (Extend for IPv6)
+ if ((client_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
+ {
+ printf("[DEBUG] Error creating server-to-server socket.\n");
+ continue;
+ }
+ // Set host (IPv4)
+ memset(&addr4, 0, sizeof(addr4));
+ addr4.sin_family = AF_INET;
+ memcpy(&addr4.sin_addr.s_addr, host.addr, 4);
+ addr4.sin_port = host.port;
+ // Connect to server
+ setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, &connect_timeout, sizeof(connect_timeout));
+ setsockopt(client_sock, SOL_SOCKET, SO_SNDTIMEO, &connect_timeout, sizeof(connect_timeout));
+ if (connect(client_sock, (struct sockaddr *)&addr4, sizeof(addr4)) < 0)
+ {
+ printf("[DEBUG] Could not connect to other server...\n");
+ close(client_sock); // TODO: Remove from alt server list if failed too often
+ continue;
+ }
+ // Apply read/write timeout
+ setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, &client_timeout, sizeof(client_timeout));
+ setsockopt(client_sock, SOL_SOCKET, SO_SNDTIMEO, &client_timeout, sizeof(client_timeout));
+ //
+ // TODO: Send and receive info from server
+ //
+ close(client_sock);
+ //
+ // TODO: Process data, update server info, add/remove this server as alt server for images, replicate images, etc.
+ }
}
/**
* Get full name of an available dnbd3 device, eg. /dev/dnbd4
* Returned buffer is owned by this module, do not modify or free!
+ * Returns NULL if all devices are in use
*/
static char *get_free_device()
{
if (devices == NULL)
return NULL;
- int i;
+ int i, c;
+ char buffer[100];
for (i = 0; i < num_devices; ++i)
{
if (!devices[i].available)
continue;
- // TODO: Check sysfs if device is maybe already connected
+ devices[i].available = FALSE;
+ // Check sysfs if device is maybe already connected
+ snprintf(buffer, 100, "/sys/devices/virtual/block/%s/net/cur_server_addr", devices[i].name + 5);
+ FILE *f = fopen(buffer, "r");
+ if (f == NULL)
+ {
+ printf("[DEBUG] Could not open %s - device marked as used.\n", buffer);
+ continue;
+ }
+ c = fgetc(f);
+ fclose(f);
+ if (c > 0)
+ {
+ // Could read something, so the device is connected
+ printf("[DEBUG] Free device %s is actually in use - marked as such.\n", devices[i].name);
+ continue;
+ }
return devices[i].name;
}
+ memlogf("[WARNING] No more free dnbd3 devices - proxy mode probably affected.");
return NULL;
}
diff --git a/src/server/net.c b/src/server/net.c
index afb7077..963d3ea 100644
--- a/src/server/net.c
+++ b/src/server/net.c
@@ -33,7 +33,7 @@
#include <netinet/tcp.h>
#include "server.h"
-#include "utils.h"
+#include "saveload.h"
#include "memlog.h"
#include "../serialize.h"
#include "../config.h"
@@ -369,7 +369,7 @@ void *dnbd3_handle_query(void *dnbd3_client)
num = 0;
for (i = 0; i < NUMBER_SERVERS; i++)
{
- if (image->servers[i].hostaddrtype == 0 || image->servers[i].failures > 200) continue;
+ if (image->servers[i].host.type == 0 || image->servers[i].failures > 200) continue;
memcpy(server_list + num++, image->servers + i, sizeof(dnbd3_server_entry_t));
}
reply.cmd = CMD_GET_SERVERS;
diff --git a/src/server/utils.c b/src/server/saveload.c
index ad40322..6af9b39 100644
--- a/src/server/utils.c
+++ b/src/server/saveload.c
@@ -24,147 +24,20 @@
#include <pthread.h>
#include <string.h>
#include <glib.h>
+#include <math.h>
#include <netinet/in.h>
-#include <arpa/inet.h>
#include "server.h"
-#include "utils.h"
+#include "saveload.h"
#include "memlog.h"
+#include "helper.h"
// Keep parsed config file in memory so it doesn't need to be parsed again every time it's modified
static GKeyFile *_config_handle = NULL;
-static char parse_address(char *string, uint8_t *af, uint8_t *addr, uint16_t *port);
-static char is_valid_namespace(char *namespace);
-static char is_valid_imagename(char *namespace);
-static void strtolower(char *string);
-static dnbd3_image_t *prepare_image(char *image_name, int rid, char *image_file, char *cache_file, gchar **servers, gsize num_servers);
-static int save_config();
+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);
-/**
- * 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
- */
-static char parse_address(char *string, uint8_t *af, uint8_t *addr, uint16_t *port)
-{
- struct in_addr v4;
- struct in6_addr v6;
-
- // Try IPv4 without port
- if (1 == inet_pton(AF_INET, string, &v4))
- {
- *af = AF_INET;
- memcpy(addr, &v4, 4);
- *port = htons(PORT);
- return 1;
- }
- // Try IPv6 without port
- if (1 == inet_pton(AF_INET6, string, &v6))
- {
- *af = AF_INET6;
- memcpy(addr, &v6, 16);
- *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
- *port = htons((uint16_t)p);
-
- // Try IPv4 with port
- if (1 == inet_pton(AF_INET, string, &v4))
- {
- *af = AF_INET;
- memcpy(addr, &v4, 4);
- return 1;
- }
- // Try IPv6 with port
- if (1 == inet_pton(AF_INET6, string, &v6))
- {
- *af = AF_INET6;
- memcpy(addr, &v6, 16);
- return 1;
- }
-
- // FAIL
- return 0;
-}
-
-static char is_valid_namespace(char *namespace)
-{
- if (*namespace == '\0' || *namespace == '/')
- return 0; // Invalid: Length = 0 or starting with a slash
- while (*namespace)
- {
- if (*namespace != '/' && *namespace != '-' && (*namespace < 'a' || *namespace > 'z')
- && (*namespace < 'A' || *namespace > 'Z')
- && (*namespace < '0' || *namespace > '9'))
- return 0;
- ++namespace;
- }
- if (*(namespace - 1) == '/')
- return 0; // Invalid: Ends in a slash
- return 1;
-}
-
-static char is_valid_imagename(char *namespace)
-{
- if (*namespace == '\0' || *namespace == ' ')
- return 0; // Invalid: Length = 0 or starting with a space
- while (*namespace)
- {
- // Check for invalid chars
- if (*namespace != '.' && *namespace != '-' && *namespace != ' '
- && *namespace != '(' && *namespace != ')'
- && (*namespace < 'a' || *namespace > 'z') && (*namespace < 'A' || *namespace > 'Z')
- && (*namespace < '0' || *namespace > '9'))
- return 0;
- ++namespace;
- }
- if (*(namespace - 1) == ' ')
- return 0; // Invalid: Ends in a space
- return 1;
-}
-
-static inline int is_same_server(const dnbd3_trusted_server_t *const a, const dnbd3_trusted_server_t *const b)
-{
- return (a->hostaddrtype == b->hostaddrtype)
- && (a->port == b->port)
- && (0 == memcmp(a->hostaddr, b->hostaddr, (a->hostaddrtype == AF_INET ? 4 : 16)));
-}
-
-static void strtolower(char *string)
-{
- while (*string)
- {
- if (*string >= 'A' && *string <= 'Z')
- *string += 32;
- ++string;
- }
-}
void dnbd3_load_config()
{
@@ -191,6 +64,8 @@ void dnbd3_load_config()
_local_namespace = NULL;
}
+ srand(time(NULL));
+
_ipc_password = g_key_file_get_string(_config_handle, "settings", "password", NULL);
gchar **groups = NULL;
@@ -209,11 +84,10 @@ void dnbd3_load_config()
gchar *addr = g_key_file_get_string(_config_handle, groups[i], "address", NULL);
if (addr == NULL)
continue;
- dnbd3_trusted_server_t *server = dnbd3_get_trusted_server(addr, TRUE);
+ dnbd3_trusted_server_t *server = dnbd3_get_trusted_server(addr, TRUE, groups[i]+6);
g_free(addr);
if (server == NULL)
continue;
- server->comment = strdup(groups[i]+6);
gsize key_count;
gchar **keys = g_key_file_get_keys(_config_handle, groups[i], &key_count, NULL);
for (j = 0; j < key_count; ++j)
@@ -248,10 +122,8 @@ void dnbd3_load_config()
char *image_file = g_key_file_get_string(_config_handle, groups[i], "file", NULL);
char *cache_file = g_key_file_get_string(_config_handle, groups[i], "cache", NULL);
- gsize num_servers;
- gchar **servers = g_key_file_get_string_list(_config_handle, groups[i], "servers", &num_servers, NULL);
- dnbd3_image_t *image = prepare_image(groups[i], rid, image_file, cache_file, servers, num_servers);
+ dnbd3_image_t *image = prepare_image(groups[i], rid, image_file, cache_file);
if (image)
{
_dnbd3_images = g_slist_prepend(_dnbd3_images, image);
@@ -259,7 +131,6 @@ void dnbd3_load_config()
g_free(image_file);
g_free(cache_file);
- g_strfreev(servers);
}
g_strfreev(groups);
@@ -280,7 +151,7 @@ int dnbd3_add_image(dnbd3_image_t *image)
image->rid = 1;
}
- dnbd3_image_t *newimage = prepare_image(image->config_group, image->rid, image->file, image->cache_file, NULL, 0);
+ dnbd3_image_t *newimage = prepare_image(image->config_group, image->rid, image->file, image->cache_file);
if (newimage)
{
_dnbd3_images = g_slist_prepend(_dnbd3_images, image);
@@ -299,7 +170,7 @@ int dnbd3_add_image(dnbd3_image_t *image)
pthread_spin_unlock(&_spinlock);
- const int ret = save_config();
+ const int ret = dnbd3_save_config();
if (ret == ERROR_OK)
memlogf("[INFO] Added new image '%s' (rid %d)", newimage->config_group, newimage->rid);
else
@@ -328,7 +199,7 @@ int dnbd3_del_image(dnbd3_image_t *image)
dnbd3_exec_delete(FALSE);
existing_image = NULL;
- const int ret = save_config();
+ const int ret = dnbd3_save_config();
if (ret == ERROR_OK)
memlogf("[INFO] Marked for deletion: '%s' (rid %d)", image->config_group, image->rid);
else
@@ -336,7 +207,7 @@ int dnbd3_del_image(dnbd3_image_t *image)
return ret;
}
-static int save_config()
+int dnbd3_save_config()
{
pthread_spin_lock(&_spinlock);
char *data = (char *)g_key_file_to_data(_config_handle, NULL, NULL);
@@ -408,12 +279,12 @@ dnbd3_image_t *dnbd3_get_image(char *name_orig, int rid, const char do_lock)
void dnbd3_handle_sigpipe(int signum)
{
- memlogf("ERROR: SIGPIPE received!\n");
+ memlogf("ERROR: SIGPIPE received (%s)", strsignal(signum));
}
void dnbd3_handle_sigterm(int signum)
{
- memlogf("INFO: SIGTERM or SIGINT received!\n");
+ memlogf("INFO: SIGTERM or SIGINT received (%s)", strsignal(signum));
dnbd3_cleanup();
}
@@ -423,9 +294,9 @@ void dnbd3_handle_sigterm(int signum)
* Note: This function calls dnbd3_get_image without locking, so make sure you lock
* before calling this function while the server is active.
*/
-static dnbd3_image_t *prepare_image(char *image_name, int rid, char *image_file, char *cache_file, gchar **servers, gsize num_servers)
+static dnbd3_image_t *prepare_image(char *image_name, int rid, char *image_file, char *cache_file)
{
- int j, k;
+ int j;
if (image_name == NULL)
{
memlogf("[ERROR] Null Image-Name");
@@ -511,19 +382,6 @@ static dnbd3_image_t *prepare_image(char *image_name, int rid, char *image_file,
image->working = 1;
}
- // A list of servers that are known to also host or relay this image
- if (servers)
- for (k = 0, j = 0; j < MIN(num_servers, NUMBER_SERVERS); ++j)
- {
- if (parse_address(servers[j], &(image->servers[k].hostaddrtype), image->servers[k].hostaddr,
- &(image->servers[k].port)))
- {
- ++k;
- continue;
- }
- image->servers[k].hostaddrtype = 0;
- }
-
if (image->cache_file)
{
// Determine size of cached image
@@ -637,7 +495,7 @@ void dnbd3_exec_delete(int save_if_changed)
continue;
// Kill client's connection
*ipstr = '\0';
- inet_ntop(client->addrtype, client->ipaddr, ipstr, 100);
+ host_to_string(&client->host, ipstr, 100);
memlogf("[INFO] delete_hard of %s reached; dropping client %s", image->config_group, ipstr);
const int fd = client->sock;
client->sock = -1;
@@ -645,7 +503,7 @@ void dnbd3_exec_delete(int save_if_changed)
delete_now = FALSE; // Wait for all clients being actually dropped; deletion will happen on next dnbd3_exec_delete()
}
} // END delete_hard image
- else if (image->delete_soft != 0 && image->delete_soft < now)
+ else if (image->delete_soft != 0 && image->delete_soft < now && image->atime + 3600 < now)
{
// Image should be soft-deleted
// Check if it is still in use
@@ -683,7 +541,7 @@ void dnbd3_exec_delete(int save_if_changed)
pthread_spin_lock(&_spinlock);
if (changed && save_if_changed)
- save_config();
+ dnbd3_save_config();
}
/**
@@ -693,11 +551,11 @@ void dnbd3_exec_delete(int save_if_changed)
* Returns NULL otherwise, or if the address could not be parsed
* !! Lock before calling this function !!
*/
-dnbd3_trusted_server_t *dnbd3_get_trusted_server(char *address, char create_if_not_found)
+dnbd3_trusted_server_t *dnbd3_get_trusted_server(char *address, char create_if_not_found, char *comment)
{
dnbd3_trusted_server_t server;
memset(&server, 0, sizeof(server));
- if (!parse_address(address, &server.hostaddrtype, server.hostaddr, &server.port))
+ if (!parse_address(address, &server.host))
{
memlogf("[WARNING] Could not parse address '%s' of trusted server", address);
return NULL;
@@ -711,6 +569,22 @@ dnbd3_trusted_server_t *dnbd3_get_trusted_server(char *address, char create_if_n
}
if (!create_if_not_found)
return NULL;
+ char *groupname = NULL;
+ if (comment == NULL)
+ {
+ groupname = malloc(50);
+ snprintf(groupname, 50, "trust:%x%x", rand(), (int)clock());
+ }
+ else
+ {
+ const size_t len = strlen(comment) + 8;
+ groupname = malloc(len);
+ snprintf(groupname, len, "trust:%s", comment);
+ }
+ char addrbuffer[50];
+ host_to_string(&server.host, addrbuffer, 50);
+ g_key_file_set_string(_config_handle, groupname, "address", addrbuffer);
+ free(groupname);
dnbd3_trusted_server_t *copy = malloc(sizeof(server));
memcpy(copy, &server, sizeof(*copy));
_trusted_servers = g_slist_prepend(_trusted_servers, copy);
diff --git a/src/server/utils.h b/src/server/saveload.h
index e254cfd..065c0b1 100644
--- a/src/server/utils.h
+++ b/src/server/saveload.h
@@ -42,6 +42,8 @@
#define ERROR_WRONG_PASSWORD 12
void dnbd3_load_config();
+int dnbd3_save_config();
+
int dnbd3_add_image(dnbd3_image_t *image);
int dnbd3_del_image(dnbd3_image_t *image);
@@ -49,7 +51,7 @@ void dnbd3_exec_delete(int save_if_changed);
dnbd3_image_t *dnbd3_get_image(char *name, int rid, const char do_lock);
-dnbd3_trusted_server_t *dnbd3_get_trusted_server(char *address, char create_if_not_found);
+dnbd3_trusted_server_t *dnbd3_get_trusted_server(char *address, char create_if_not_found, char *comment);
int dnbd3_add_trusted_namespace(dnbd3_trusted_server_t *server, char *namespace, char *flags);
void dnbd3_handle_sigpipe(int signum);
diff --git a/src/server/server.c b/src/server/server.c
index 9fc5383..4b30009 100644
--- a/src/server/server.c
+++ b/src/server/server.c
@@ -31,7 +31,7 @@
#include "../version.h"
#include "server.h"
-#include "utils.h"
+#include "saveload.h"
#include "net.h"
#include "ipc.h"
#include "memlog.h"
@@ -245,10 +245,11 @@ int main(int argc, char *argv[])
continue;
}
// TODO: Extend this if you ever want to add IPv6 (something like:)
- // dnbd3_client->addrtype = AF_INET6;
- // memcpy(dnbd3_client->ipaddr, &(client.sin6_addr), 16);
- dnbd3_client->addrtype = AF_INET;
- memcpy(dnbd3_client->ipaddr, &(client.sin_addr), 4);
+ // dnbd3_client->host.type = AF_INET6;
+ // memcpy(dnbd3_client->host.addr, &(client.sin6_addr), 16);
+ dnbd3_client->host.type = AF_INET;
+ memcpy(dnbd3_client->host.addr, &(client.sin_addr), 4);
+ dnbd3_client->host.port = client.sin_port;
dnbd3_client->sock = fd;
dnbd3_client->image = NULL;
diff --git a/src/server/server.h b/src/server/server.h
index c608066..93f219e 100644
--- a/src/server/server.h
+++ b/src/server/server.h
@@ -28,37 +28,28 @@
#include "../config.h"
#include "../types.h"
-// one byte in the map covers 8 4kib blocks, so 32kib per byte
-// "+ (1 << 15) - 1" is required to account for the last bit of
-// the image that is smaller than 32kib
-// this would be the case whenever the image file size is not a
-// multiple of 32kib (= the number of blocks is not divisible by 8)
-// ie: if the image is 49152 bytes and you do 49152 >> 15 you get 1,
-// but you actually need 2 bytes to have a complete cache map
-#define IMGSIZE_TO_MAPBYTES(bytes) ((int)(((bytes) + (1 << 15) - 1) >> 15))
typedef struct
{
- char *config_group; // exact name of group in config file that represents this image
- char *low_name; // full (global) name of image, lowercased for comparison, eg. "uni-freiburg/rz/ubuntu-12.04"
- int rid; // revision of provided image
- char *file; // path to image file or device
- uint64_t filesize; // size of image
+ char *config_group; // exact name of group in config file that represents this image
+ char *low_name; // full (global) name of image, lowercased for comparison, eg. "uni-freiburg/rz/ubuntu-12.04"
+ int rid; // revision of provided image
+ char *file; // path to image file or device
+ uint64_t filesize; // size of image
dnbd3_server_entry_t servers[NUMBER_SERVERS]; // known alt servers that also offer that image
- time_t atime; // last access time
- uint8_t *cache_map; // cache map telling which parts are locally cached
- char *cache_file; // path to local cache of image (in case the image is read from a dnbd3 device)
- char working; // whether this image is considered working. local images are "working" if the local file exists, proxied images have to have at least one working upstream server or a complete local cache file
- time_t delete_soft; // unixtime telling when this image should be deleted. if there are still clients using this image it weill be kept, but new clients requesting the image will be rejected. 0 = never
- time_t delete_hard; // unixtime telling when this image should be deleted, no matter if there are still clients connected. 0 = never
- uint8_t relayed; // TRUE if relayed from other server (needs dnbd3 client module loaded)
+ time_t atime; // last access time
+ uint8_t *cache_map; // cache map telling which parts are locally cached
+ char *cache_file; // path to local cache of image (in case the image is read from a dnbd3 device)
+ char working; // whether this image is considered working. local images are "working" if the local file exists, proxied images have to have at least one working upstream server or a complete local cache file
+ time_t delete_soft; // unixtime telling when this image should be deleted. if there are still clients using this image it weill be kept, but new clients requesting the image will be rejected. 0 = never
+ time_t delete_hard; // unixtime telling when this image should be deleted, no matter if there are still clients connected. 0 = never
+ uint8_t relayed; // TRUE if relayed from other server (needs dnbd3 client module loaded)
} dnbd3_image_t;
typedef struct
{
int sock;
- uint8_t ipaddr[16];
- uint8_t addrtype; // ip version (AF_INET or AF_INET6)
+ dnbd3_host_t host;
uint8_t is_server; // TRUE if a server in proxy mode, FALSE if real client
pthread_t thread;
dnbd3_image_t *image;
@@ -66,11 +57,9 @@ typedef struct
typedef struct
{
- uint8_t hostaddr[16];
- uint16_t port;
- uint8_t hostaddrtype;
+ dnbd3_host_t host;
gchar *comment;
- GSList *namespaces; // List of dnbd3_namespace_t
+ GSList *namespaces; // List of dnbd3_namespace_t
} dnbd3_trusted_server_t;
typedef struct
diff --git a/src/server/xmlutil.h b/src/server/xmlutil.h
index 46a5790..971d8a9 100644
--- a/src/server/xmlutil.h
+++ b/src/server/xmlutil.h
@@ -22,5 +22,17 @@ xmlChar *getTextFromPath(xmlDocPtr doc, char *xpath);
xmlXPathFreeContext(_makro_xpathCtx); \
} while(0)
+#define NUM_POINTERS_IN_LIST 20
+#define NEW_POINTERLIST \
+ void *_makro_ptrlist[NUM_POINTERS_IN_LIST]; \
+ int _makro_usedcount = 0
+
+#define FREE_POINTERLIST do { \
+ int _makro_i_; \
+ for (_makro_i_ = 0; _makro_i_ < _makro_usedcount; ++_makro_i_) { \
+ xmlFree(_makro_ptrlist[_makro_i_]); \
+ } } while(0)
+
+#define XML_GETPROP(_node, _name) (xmlChar*)(_makro_ptrlist[(_makro_usedcount >= NUM_POINTERS_IN_LIST ? 0 : _makro_usedcount++)] = xmlGetNoNsProp(_node, BAD_CAST _name))
#endif
diff --git a/src/types.h b/src/types.h
index d41111a..22fbc50 100644
--- a/src/types.h
+++ b/src/types.h
@@ -60,12 +60,19 @@ static const uint16_t dnbd3_packet_magic = (0x73) | (0x72 << 8);
#error "Unknown Endianness"
#endif
+#pragma pack(1)
+typedef struct
+{
+ uint8_t addr[16]; // 16byte (network representation, so it can be directly passed to socket functions)
+ uint16_t port; // 2byte (network representation, so it can be directly passed to socket functions)
+ uint8_t type; // 1byte (ip version. AF_INET or AF_INET6. 0 means this struct is empty and should be ignored)
+} dnbd3_host_t;
+#pragma pack(0)
+
typedef struct
{
uint16_t len;
- uint8_t addrtype;
- uint8_t addr[16]; // network representation
- uint16_t port; // network representation
+ dnbd3_host_t host;
uint16_t imgnamelen;
char *imgname;
int rid;
@@ -106,10 +113,8 @@ typedef struct
#pragma pack(1)
typedef struct
{
- uint8_t hostaddr[16]; // 16byte (network representation, so it can be directly passed to socket functions)
- uint16_t port; // 2byte (network representation, so it can be directly passed to socket functions)
- uint8_t hostaddrtype; // 1byte (ip version. AF_INET or AF_INET6. 0 means this struct is empty and should be ignored)
- uint8_t failures; // 1byte (number of times server has been consecutively unreachable)
+ dnbd3_host_t host;
+ uint8_t failures; // 1byte (number of times server has been consecutively unreachable)
} dnbd3_server_entry_t;
#pragma pack(0)