summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--LOCKS4
-rw-r--r--src/config.h9
-rw-r--r--src/server/image.c38
-rw-r--r--src/server/image.h8
-rw-r--r--src/server/job.c772
-rw-r--r--src/server/job.h7
-rw-r--r--src/server/net.c2
-rw-r--r--src/server/net.h2
-rw-r--r--src/server/rpc.c810
-rw-r--r--src/server/rpc.h55
-rw-r--r--src/server/saveload.c734
-rw-r--r--src/server/saveload.h63
-rw-r--r--src/server/server.c63
-rw-r--r--src/server/server.h62
-rw-r--r--src/server/sockhelper.h12
-rw-r--r--src/server/xmlutil.c43
-rw-r--r--src/server/xmlutil.h55
18 files changed, 148 insertions, 2593 deletions
diff --git a/.gitignore b/.gitignore
index cea98b8..97b41dc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
build/
.cproject
.project
+*.swp
+.autotools
diff --git a/LOCKS b/LOCKS
index 689dd06..d6085c5 100644
--- a/LOCKS
+++ b/LOCKS
@@ -12,6 +12,10 @@ This is a list of used locks, in the order they
have to be aquired if you must hold multiple locks:
_clients_lock
_clients[].lock
+_images_lock
+_images[].lock
+_alts_lock
+
If you need to lock multiple clients at once,
lock the client with the lowest array index first.
diff --git a/src/config.h b/src/config.h
index 2668410..a59f7bc 100644
--- a/src/config.h
+++ b/src/config.h
@@ -21,9 +21,15 @@
#ifndef CONFIG_H_
#define CONFIG_H_
+// +++++ Performance related
+#define SERVER_MAX_CLIENTS 5000
+#define SERVER_MAX_IMAGES 5000
+#define SERVER_MAX_ALTS 1000
+
// +++++ Network +++++
// Default port
#define PORT 5003
+#define RPC_PORT (PORT+1)
// Protocol version should be increased whenever new features/messages are added,
// so either the client or server can run in compatibility mode, or they can
@@ -33,6 +39,8 @@
#define MIN_SUPPORTED_CLIENT 2
// Which is the minimum protocol version the client expects from the server
#define MIN_SUPPORTED_SERVER 2
+// Length of comment fields (for alt server etc.)
+#define COMMENT_LENGTH 120
// No payload allowed exceeding this many bytes (actual data from client->server is not affected by this limit!)
#define MAX_PAYLOAD 1000
@@ -69,6 +77,5 @@
// +++++ Misc +++++
#define DEFAULT_SERVER_CONFIG_FILE "/etc/dnbd3/server.conf"
#define DEFAULT_CLIENT_CONFIG_FILE "/etc/dnbd3/client.conf"
-#define MAX_RPC_PAYLOAD 3000
#endif /* CONFIG_H_ */
diff --git a/src/server/image.c b/src/server/image.c
new file mode 100644
index 0000000..8a2b943
--- /dev/null
+++ b/src/server/image.c
@@ -0,0 +1,38 @@
+#include "image.h"
+
+#include <glib/gmacros.h>
+#include <assert.h>
+
+int image_is_complete(dnbd3_image_t *image)
+{
+ assert(image != NULL);
+ if (image->working && image->cache_map == NULL) {
+ return TRUE;
+ }
+ if (image->filesize == 0 || !image->working) {
+ return FALSE;
+ }
+ int complete = TRUE, j;
+ const int map_len_bytes = IMGSIZE_TO_MAPBYTES(image->filesize);
+ for (j = 0; j < map_len_bytes - 1; ++j)
+ {
+ if (image->cache_map[j] != 0xFF)
+ {
+ complete = FALSE;
+ break;
+ }
+ }
+ if (complete) // Every block except the last one is complete
+ { // Last one might need extra treatment if it's not a full byte
+ const int blocks_in_last_byte = (image->filesize >> 12) & 7;
+ uint8_t last_byte = 0;
+ if (blocks_in_last_byte == 0) {
+ last_byte = 0xFF;
+ } else {
+ for (j = 0; j < blocks_in_last_byte; ++j)
+ last_byte |= (1 << j);
+ }
+ complete = ((image->cache_map[map_len_bytes - 1] & last_byte) == last_byte);
+ }
+ return complete;
+}
diff --git a/src/server/image.h b/src/server/image.h
new file mode 100644
index 0000000..ea09940
--- /dev/null
+++ b/src/server/image.h
@@ -0,0 +1,8 @@
+#ifndef _IMAGE_H_
+#define _IMAGE_H_
+
+#include "server.h"
+
+int image_is_complete(dnbd3_image_t *image);
+
+#endif
diff --git a/src/server/job.c b/src/server/job.c
deleted file mode 100644
index 31f577b..0000000
--- a/src/server/job.c
+++ /dev/null
@@ -1,772 +0,0 @@
-#include "job.h"
-#include "saveload.h"
-#include "helper.h"
-#include "memlog.h"
-#include "rpc.h"
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <linux/fs.h>
-#include <pthread.h>
-#include "sockhelper.h"
-
-#include <glib/gslist.h>
-
-#include <libxml/parser.h>
-#include <libxml/xpath.h>
-#include "xmlutil.h"
-#include "../config.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
-
-#ifndef FALSE
-#define FALSE (0)
-#endif
-
-#ifndef TRUE
-#define TRUE (!FALSE)
-#endif
-
-typedef struct
-{
- char available;
- char name[DEV_STRLEN];
-} device_t;
-
-// "/dev/dnbdXX" == 11 bytes per device + nullchar = 12
-static device_t *devices = NULL;
-static int num_devices = 0;
-static char keep_running = TRUE;
-
-// Private functions
-static char *get_free_device();
-static void return_free_device(char *name);
-static void connect_proxy_images();
-static void query_servers();
-static char *create_cache_filename(char *name, int rid, char *buffer, int maxlen);
-static void add_alt_server(dnbd3_image_t *image, dnbd3_host_t *host);
-static void remove_alt_server(dnbd3_trusted_server_t *server);
-static void dnbd3_update_atimes(time_t now);
-
-//
-
-void *dnbd3_job_thread(void *data)
-{
- int i, j;
- // Determine number of available dnbd3 devices, which are needed for proxy mode
- char dev[DEV_STRLEN];
- for (i = 0; i < MAX_NUM_DEVICES_TO_CHECK; ++i)
- {
- snprintf(dev, DEV_STRLEN, "/dev/dnbd%d", i);
- if (access(dev, W_OK | R_OK)) // Need RW access to device to read and do ioctl
- continue;
- ++num_devices;
- }
- if (num_devices > 0)
- {
- devices = calloc(num_devices, sizeof(*devices));
- for (i = 0, j = 0; i < MAX_NUM_DEVICES_TO_CHECK; ++i)
- {
- memset(dev, 0, DEV_STRLEN);
- snprintf(dev, DEV_STRLEN, "/dev/dnbd%d", i);
- if (access(dev, W_OK | R_OK))
- continue;
- if (j >= num_devices) // More available devices during second iteration? :-(
- break;
- memcpy(devices[j].name, dev, DEV_STRLEN);
- devices[j].available = TRUE;
- ++j;
- }
- num_devices = j;
- }
- memlogf("[INFO] %d available dnbd3 devices for proxy mode", num_devices);
- //
- time_t next_delete_invocation = 0;
- //
- // Job/Watchdog mainloop
- while (keep_running)
- {
- const time_t starttime = time(NULL);
- //
- // Update image atime
- dnbd3_update_atimes(starttime);
- // Call image deletion function if last call is more than 5 minutes ago
- if (starttime > next_delete_invocation)
- {
- next_delete_invocation = starttime + 300;
- dnbd3_exec_delete(TRUE);
- }
- // Check for proxied images that have not been set up yet
- connect_proxy_images();
- // TODO: Replicate proxied images (limited bandwidth)
- // Query other servers for new images/status/...
- query_servers();
- // TODO: Switch server of dnbd device based on more sophisticated inputs than just rtt
- // Calc sleep timeout for next iteration
- sleep(30 - (time(NULL) - starttime)); // Sleep 30 seconds, but account for the time it took to execute the loop
- }
- //
- free(devices);
- devices = NULL;
- pthread_exit(NULL);
- return NULL;
-}
-
-void dnbd3_job_shutdown()
-{
- keep_running = FALSE;
-}
-
-static void connect_proxy_images()
-{
- int s, n;
- dnbd3_server_entry_t servers[NUMBER_SERVERS];
- char imagename[1000];
- int rid;
- dnbd3_ioctl_t msg;
- memset(&msg, 0, sizeof(dnbd3_ioctl_t));
- msg.len = (uint16_t)sizeof(dnbd3_ioctl_t);
- msg.read_ahead_kb = DEFAULT_READ_AHEAD_KB;
- msg.is_server = TRUE;
- for (n = 0 ;; ++n) // Iterate over all images
- {
- pthread_spin_lock(&_spinlock);
- dnbd3_image_t *image = g_slist_nth_data(_dnbd3_images, n);
- if (image == NULL)
- { // End of list reached
- pthread_spin_unlock(&_spinlock);
- break;
- }
- if (image->working && image->cache_map && image->file)
- { // Image is relayed and already connected, check if cache is complete
- int complete = TRUE, j;
- const int map_len_bytes = IMGSIZE_TO_MAPBYTES(image->filesize);
- for (j = 0; j < map_len_bytes - 1; ++j)
- {
- if (image->cache_map[j] != 0xFF)
- {
- complete = FALSE;
- break;
- }
- }
- if (complete) // Every block except the last one is complete
- { // Last one might need extra treatment if it's not a full byte
- const int blocks_in_last_byte = (image->filesize >> 12) & 7;
- uint8_t last_byte = 0;
- if (blocks_in_last_byte == 0)
- last_byte = 0xFF;
- else
- for (j = 0; j < blocks_in_last_byte; ++j)
- last_byte |= (1 << j);
- complete = ((image->cache_map[map_len_bytes - 1] & last_byte) == last_byte);
- }
- if (!complete) // Image is not complete, finished handling it
- {
- pthread_spin_unlock(&_spinlock);
- continue;
- }
- // Image is 100% cached, disconnect dnbd3 device
- memlogf("[INFO] Disconnecting %s because local copy of %s is complete.", image->file, image->config_group);
- int dh = open(image->file, O_RDONLY);
- if (dh < 0)
- memlogf("[ERROR] Could not open() device '%s'", image->file);
- else
- {
- if (ioctl(dh, IOCTL_CLOSE, (void*)0) != 0)
- memlogf("[ERROR] Could not IOCTL_CLOSE device '%s'", image->file);
- else
- return_free_device(image->file);
- close(dh);
- }
- free(image->file);
- image->file = NULL;
- pthread_spin_unlock(&_spinlock);
- continue;
- }
- if (image->working || image->file || image->low_name == NULL)
- { // Image is a local one, nothing to do
- pthread_spin_unlock(&_spinlock);
- continue;
- }
- // Image is relayed and not connected yet
- char *devname = get_free_device();
- if (devname == NULL)
- { // All devices busy, can't connect
- pthread_spin_unlock(&_spinlock);
- continue;
- }
- // Remember image information as the image pointer isn't
- // guaranteed to stay valid after unlocking
- snprintf(imagename, 1000, "%s", image->low_name);
- rid = image->rid;
- memcpy(servers, image->servers, sizeof(servers[0]) * NUMBER_SERVERS);
- pthread_spin_unlock(&_spinlock);
- int dh = open(devname, O_RDWR);
- if (dh < 0) // Open device so we can issue ioctls to it
- {
- pthread_spin_lock(&_spinlock);
- return_free_device(devname); // Failed :-(
- pthread_spin_unlock(&_spinlock);
- continue;
- }
- for (s = 0; s < NUMBER_SERVERS; ++s)
- { // Try to connect to any of the alt servers known for that image
- if (servers[s].host.type == 0)
- continue;
- // connect device
- printf("[DEBUG] Connecting device....\n");
- msg.host = servers[s].host;
- msg.imgname = imagename;
- msg.imgnamelen = strlen(imagename);
- msg.rid = rid;
- if (ioctl(dh, IOCTL_OPEN, &msg) < 0)
- continue;
- printf("[DEBUG] Connected! Adding alt servers...\n");
- // connected. we manually add all known alt servers to this
- // device, so even if the initial server doesn't consider some
- // of those as trusted servers, they are still used for failover/load balancing
- for (++s; s < NUMBER_SERVERS; ++s)
- {
- if (servers[s].host.type == 0)
- continue;
- msg.host = servers[s].host;
- if (ioctl(dh, IOCTL_ADD_SRV, &msg) < 0)
- memlogf("[WARNING] Could not add alt server to proxy device");
- else
- printf("[DEBUG] Added an alt server\n");
- }
- printf("[DEBUG] Done, handling file size...\n");
- // LOCK + UPDATE
- int isworking = FALSE, alloc_cache = FALSE;
- pthread_spin_lock(&_spinlock);
- if (g_slist_find(_dnbd3_images, image) == NULL)
- { // Image not in list anymore, was deleted in meantime...
- if (ioctl(dh, IOCTL_CLOSE, &msg) < 0)
- memlogf("[WARNING] Could not close device after use - lost %s", devname);
- else
- return_free_device(devname);
- pthread_spin_unlock(&_spinlock);
- break;
- }
- // Image still exists
- image->file = strdup(devname);
- long long oct = 0;
- int t, ret;
- for (t = 0; t < 10 && dh >= 0; ++t)
- { // For some reason the getsize-ioctl might return 0 right after connecting
- // No idea why this happen. Maybe the IOCTL_OPEN call returns before the
- // connection is fully established, but I have no idea why.
- // So let's retry a couple of times if it fails.
- ret = ioctl(dh, BLKGETSIZE64, &oct);
- if (ret == 0 && oct > 0)
- break;
- close(dh);
- usleep(100 * 1000);
- dh = open(devname, O_RDONLY);
- }
- if (dh < 0 || ret != 0)
- memlogf("[ERROR] SIZE fail on %s (ret=%d, oct=%lld)", devname, ret, oct);
- else if (oct == 0)
- memlogf("[ERROR] Reported disk size is 0.");
- else if (image->filesize != 0 && image->filesize != oct)
- memlogf("[ERROR] Remote and local size of image do not match: %llu != %llu for %s", (unsigned long long)oct, (unsigned long long)image->filesize, image->low_name);
- else
- isworking = TRUE;
- image->filesize = (uint64_t)oct;
- if (image->cache_file != NULL && isworking && image->cache_map == NULL)
- {
- printf("[DEBUG] Image has cache file %s\n", image->cache_file);
- const int mapsize = IMGSIZE_TO_MAPBYTES(image->filesize);
- image->cache_map = calloc(mapsize, 1);
- off_t cachelen = -1;
- int ch = open(image->cache_file, O_RDONLY);
- if (ch >= 0)
- {
- cachelen = lseek(ch, 0, SEEK_END);
- close(ch);
- }
- if (ch < 0 || cachelen != image->filesize)
- alloc_cache = TRUE;
- if (cachelen == image->filesize)
- {
- char mapfile[strlen(image->cache_file) + 5];
- sprintf(mapfile, "%s.map", image->cache_file);
- int cmh = open(mapfile, O_RDONLY);
- if (cmh >= 0)
- {
- if (lseek(cmh, 0, SEEK_END) != mapsize)
- memlogf("[WARNING] Existing cache map has wrong size.");
- else
- {
- lseek(cmh, 0, SEEK_SET);
- read(cmh, image->cache_map, mapsize);
- printf("[DEBUG] Found existing cache file and map for %s\n", image->low_name);
- }
- close(cmh);
- }
- }
- }
- char cfname[1000] = {0};
- off_t fs = image->filesize;
- if (isworking && !(alloc_cache && image->cache_file))
- {
- image->working = TRUE;
- if (!image->cache_file) // This should be removed. proxy with no cache is completely pointless.
- memlogf("[WARNING] Proxy-Mode enabled without cache directory. This will most likely hurt performance.");
- goto continue_with_next_image;
- }
- snprintf(cfname, 1000, "%s", image->cache_file);
- pthread_spin_unlock(&_spinlock);
- if (isworking && *cfname)
- {
- int ch = open(cfname, O_WRONLY | O_CREAT, 0600);
- if (ch >= 0)
- {
- // Pre-allocate disk space
- // TODO: Check if this has a performance impact on the rest of the server (ie. client lag)
- // If so, do this gracefully by incrementing size and sleeping in between.
- printf("[DEBUG] Pre-allocating disk space...\n");
- lseek(ch, fs - 1, SEEK_SET);
- write(ch, &ch, 1);
- close(ch);
- printf("[DEBUG] Allocation complete.\n");
- pthread_spin_lock(&_spinlock);
- if (g_slist_find(_dnbd3_images, image) != NULL)
- {
- image->working = TRUE;
- memlogf("[INFO] Enabled relayed image %s (%lld)", image->low_name, (long long)fs);
- goto continue_with_next_image;
- }
- unlink(cfname);
- memlogf("[WARNING] Image has gone away");
- pthread_spin_unlock(&_spinlock);
- }
- else
- memlogf("[WARNING] Could not pre-allocate %s", cfname);
- }
- break;
- } // <-- end of loop over servers
- // If this point is reached, setting up replication was not successful,
- // so lock and free the filename allocated earlier, and return the device.
- pthread_spin_lock(&_spinlock);
- if (g_slist_find(_dnbd3_images, image) != NULL)
- {
- free(image->file);
- image->file = NULL;
- }
- return_free_device(devname);
-continue_with_next_image:
- pthread_spin_unlock(&_spinlock);
- close(dh);
- }
-}
-
-static void dnbd3_update_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()
-{
- if (_trusted_servers == NULL)
- return;
- int client_sock, num;
- dnbd3_trusted_server_t *server;
- dnbd3_host_t host;
- char xmlbuffer[MAX_RPC_PAYLOAD];
- for (num = 0;; ++num)
- {
- // "Iterate" this way to prevent holding the lock for a long time,
- // although there is a very small chance 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
- }
- host = server->host; // Copy host, in case server gets deleted by another thread while processing continues here
- pthread_spin_unlock(&_spinlock);
- // Connect
- host.port = htons(ntohs(host.port) + 1); // RPC port is client port + 1
- client_sock = sock_connect(&host, 800, 600);
- if (client_sock == -1)
- {
- char buf[100];
- if (host_to_string(&host, buf, 100))
- printf("[DEBUG] Could not connect to trusted server %s\n", buf);
- goto communication_error;
- }
- //
- // Send and receive info from server
- // Send message
- dnbd3_rpc_t header;
- header.cmd = htonl(RPC_IMG_LIST);
- header.size = 0;
- send(client_sock, (char *)&header, sizeof(header), 0);
- if (!recv_data(client_sock, &header, sizeof(header)))
- {
- printf("[DEBUG] Could not receive IMG_LIST header from a trusted server...\n");
- goto communication_error;
- }
- header.cmd = ntohl(header.cmd);
- header.size = ntohl(header.size);
- if (header.cmd != RPC_IMG_LIST)
- {
- printf("[DEBUG] Error. Reply from other server was cmd:%d, error:%d\n", (int)header.cmd, (int)-1);
- goto communication_error;
- }
- if (header.size > MAX_RPC_PAYLOAD)
- {
- memlogf("[WARNING] XML payload from other server exceeds MAX_RPC_PAYLOAD (%d > %d)", (int)header.size, (int)MAX_RPC_PAYLOAD);
- goto communication_error;
- }
- if (!recv_data(client_sock, xmlbuffer, header.size))
- {
- printf("[DEBUG] Error reading XML payload from other server.\n");
- goto communication_error;
- }
- close(client_sock);
- //
- // Process data, update server info, add/remove this server as alt server for images, replicate images, etc.
- xmlDocPtr doc = xmlReadMemory(xmlbuffer, header.size, "noname.xml", NULL, 0);
-
- if (doc == NULL)
- {
- memlogf("[WARNING] Could not parse XML data received by other server.");
- goto communication_error;
- }
- // Data seems ok
-
- xmlNodePtr cur;
- FOR_EACH_NODE(doc, "/data/images/image", cur)
- {
- if (cur->type != XML_ELEMENT_NODE)
- continue;
- NEW_POINTERLIST;
- char *image = XML_GETPROP(cur, "name");
- char *ridstr = XML_GETPROP(cur, "rid");
- char *sizestr = XML_GETPROP(cur, "size");
- if (!image || !ridstr || !sizestr)
- goto free_current_image;
- const int rid = atoi(ridstr);
- const long long size = atoll(sizestr);
- if (rid <= 0)
- {
- printf("[DEBUG] Ignoring remote image with rid %d\n", rid);
- goto free_current_image;
- }
- char *slash = strrchr(image, '/');
- if (slash == NULL)
- {
- printf("[DEBUG] Ignoring remote image with no '/' in name...\n");
- goto free_current_image;
- }
- else
- {
- *slash++ = '\0';
- if (!is_valid_namespace(image))
- {
- printf("[DEBUG] Ignoring remote image with invalid namespace '%s'\n", image);
- goto free_current_image;
- }
- if (!is_valid_imagename(slash))
- {
- printf("[DEBUG] Ignoring remote image with invalid name '%s'\n", slash);
- goto free_current_image;
- }
- snprintf(xmlbuffer, MAX_RPC_PAYLOAD, "%s/%s", image, slash);
- }
- // Image seems legit, check if there's a local copy
- dnbd3_namespace_t *trust;
- pthread_spin_lock(&_spinlock);
- trust = dnbd3_get_trust_level(&host, image);
- if (trust == NULL)
- { // Namespace of image is not trusted
- pthread_spin_unlock(&_spinlock);
- printf("[DEBUG] No NS match: '%s'\n", xmlbuffer);
- goto free_current_image;
- }
- char *sdel = XML_GETPROP(cur, "softdelete");
- char *hdel = XML_GETPROP(cur, "harddelete");
- const time_t softdelete = sdel ? atol(sdel) : 0;
- const time_t harddelete = hdel ? atol(hdel) : 0;
- dnbd3_image_t *local_image = dnbd3_get_image(xmlbuffer, rid, FALSE);
- if (local_image == NULL && trust->auto_replicate)
- {
- pthread_spin_unlock(&_spinlock);
- const time_t deadline = time(NULL) + 60;
- if ((softdelete != 0 && softdelete < deadline)
- || (harddelete != 0 && harddelete < deadline))
- { // Image is already about to be deleted, ignore it
- printf("[DEBUG] Not replicating old image: '%s'\n", xmlbuffer);
- goto free_current_image;
- }
- // Image is NEW, add it!
- dnbd3_image_t newimage;
- char cachefile[90];
- memset(&newimage, 0, sizeof(newimage));
- newimage.config_group = xmlbuffer;
- newimage.rid = rid;
- newimage.filesize = size;
- newimage.delete_hard = harddelete;
- newimage.delete_soft = softdelete;
- if (_cache_dir)
- {
- newimage.cache_file = create_cache_filename(xmlbuffer, rid, cachefile, 90);
- printf("[DEBUG] Cache file is %s\n", newimage.cache_file);
- }
- dnbd3_add_image(&newimage);
- pthread_spin_lock(&_spinlock);
- local_image = dnbd3_get_image(xmlbuffer, rid, FALSE);
- if (local_image)
- add_alt_server(local_image, &host);
- pthread_spin_unlock(&_spinlock);
- }
- else if (local_image != NULL)
- {
- // Image is already KNOWN, add alt server if appropriate
- const time_t deadline = time(NULL) + 60;
- if (softdelete == 0 || softdelete > deadline)
- {
- if (local_image->filesize == 0) // Size is unknown, just assume the trusted server got it right
- local_image->filesize = size;
- if (size != local_image->filesize)
- printf("[DEBUG] Ignoring remote image '%s' because it has a different size from the local version! (remote: %llu, local: %llu)\n", local_image->config_group, size, (unsigned long long)local_image->filesize);
- else
- add_alt_server(local_image, &host);
- }
- if (local_image->cache_file && trust->auto_replicate) {
- local_image->delete_hard = harddelete;
- local_image->delete_soft = softdelete;
- }
- pthread_spin_unlock(&_spinlock);
- }
- else
- {
- printf("[DEBUG] No NS match: '%s'\n", xmlbuffer);
- pthread_spin_unlock(&_spinlock);
- }
- // Cleanup
-free_current_image:
- FREE_POINTERLIST;
- } END_FOR_EACH;
-
-
- // ...
- xmlFreeDoc(doc);
- //
- continue;
-communication_error:
- if (client_sock != -1)
- close(client_sock);
- pthread_spin_lock(&_spinlock);
- if (g_slist_find(_trusted_servers, server))
- {
- if (server->unreachable < 10 && ++server->unreachable == 5)
- remove_alt_server(server);
- }
- pthread_spin_unlock(&_spinlock);
- }
-}
-
-static char *create_cache_filename(char *name, int rid, char *buffer, int maxlen)
-{
- if (_cache_dir == NULL)
- return NULL;
- size_t cdl = strlen(_cache_dir);
- if (maxlen < 15 + cdl)
- return NULL;
- if (strlen(name) + 16 + cdl < maxlen)
- snprintf(buffer, maxlen, "%s/%s_rid_%d.cache", _cache_dir, name, rid);
- else
- {
- char *slash = strrchr(name, '/');
- if (slash == NULL)
- {
- snprintf(buffer, maxlen - 17, "%s/%s", _cache_dir, name);
- snprintf(buffer + maxlen - 17, 17, "_rid_%d.cache", rid);
- }
- else
- {
- snprintf(buffer, maxlen, "%s/%s", _cache_dir, name);
- snprintf(buffer + cdl, maxlen - cdl, "%s_rid_%d.cache", slash, rid);
- }
- }
- char *ptr = buffer + cdl + 1;
- while (*ptr)
- {
- if (*ptr == '/' || *ptr < 32 || *ptr == ' ' || *ptr == '\\' || *ptr == '*' || *ptr == '?')
- *ptr = '_';
- ++ptr;
- }
- FILE *fh;
- while ((fh = fopen(buffer, "rb")))
- { // Alter file name as long as a file by that name already exists (el cheapo edition)
- fclose(fh);
- char *c = buffer + rand() % strlen(buffer);
- *c = rand() % 26 + 'A';
- }
- return buffer;
-}
-
-/**
- * !! Call this while holding the lock !!
- */
-static void add_alt_server(dnbd3_image_t *image, dnbd3_host_t *host)
-{
- int i;
- for (i = 0; i < NUMBER_SERVERS; ++i)
- {
- if (is_same_server(host, &image->servers[i].host))
- { // Alt server already known for this image
- if (image->servers[i].failures)
- { // It was disabled, re-enable and send info to clients
- image->servers[i].failures = 0;
- break;
- }
- else // Alt-Server already known and active, do nothing
- return;
- }
- }
- // Add to list if it wasn't in there
- if (i >= NUMBER_SERVERS)
- for (i = 0; i < NUMBER_SERVERS; ++i)
- {
- if (image->servers[i].host.type == 0)
- {
- image->servers[i].host = *host;
- image->servers[i].failures = 0;
- break;
- }
- }
- if (i >= NUMBER_SERVERS) // To many known alt servers already
- return;
- // Broadcast to connected clients. Note that 'i' now points to the new server
- printf("[DEBUG] Adding alt server to %s\n", image->low_name);
- GSList *itc;
- dnbd3_reply_t header;
- header.cmd = CMD_GET_SERVERS;
- header.magic = dnbd3_packet_magic;
- header.size = sizeof(dnbd3_server_entry_t);
- fixup_reply(header);
- for (itc = _dnbd3_clients; itc; itc = itc->next)
- {
- dnbd3_client_t *const client = itc->data;
- if (client->image == image)
- {
- // Don't send message directly as the lock is being held; instead, enqueue it
- NEW_BINSTRING(message, sizeof(header) + sizeof(image->servers[i]));
- memcpy(message->data, &header, sizeof(header));
- memcpy(message->data + sizeof(header), &image->servers[i], sizeof(image->servers[i]));
- client->sendqueue = g_slist_append(client->sendqueue, message);
- }
- }
-}
-
-/**
- * !! Call this while holding the lock !!
- */
-static void remove_alt_server(dnbd3_trusted_server_t *server)
-{
- GSList *iti, *itc;
- int i;
- dnbd3_reply_t header;
- header.cmd = CMD_GET_SERVERS;
- header.magic = dnbd3_packet_magic;
- header.size = sizeof(dnbd3_server_entry_t);
- fixup_reply(header);
- // Iterate over all images
- for (iti = _dnbd3_images; iti; iti = iti->next)
- {
- dnbd3_image_t *const image = iti->data;
- // Check if any alt_server for that image is the server to be removed
- for (i = 0; i < NUMBER_SERVERS; ++i)
- {
- if (is_same_server(&server->host, &image->servers[i].host))
- {
- // Remove server from that image and tell every connected client about it
- image->servers[i].failures = 1;
- for (itc = _dnbd3_clients; itc; itc = itc->next)
- {
- dnbd3_client_t *const client = itc->data;
- if (client->image == image)
- {
- // Don't send message directly as the lock is being held; instead, enqueue it
- NEW_BINSTRING(message, sizeof(header) + sizeof(image->servers[i]));
- memcpy(message->data, &header, sizeof(header));
- memcpy(message->data + sizeof(header), &image->servers[i], sizeof(image->servers[i]));
- client->sendqueue = g_slist_append(client->sendqueue, message);
- }
- }
- image->servers[i].host.type = 0;
- }
- }
- }
-}
-
-/**
- * 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, c;
- char buffer[100];
- for (i = 0; i < num_devices; ++i)
- {
- if (!devices[i].available)
- continue;
- 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;
-}
-
-static void return_free_device(char *name)
-{
- if (devices == NULL)
- return;
- int i;
- for (i = 0; i < num_devices; ++i)
- {
- if (devices[i].available || strcmp(devices[i].name, name) != 0)
- continue;
- devices[i].available = TRUE;
- break;
- }
-}
diff --git a/src/server/job.h b/src/server/job.h
deleted file mode 100644
index 8072148..0000000
--- a/src/server/job.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef JOB_H_
-#define JOB_H_
-
-void *dnbd3_job_thread(void *data);
-void dnbd3_job_shutdown();
-
-#endif
diff --git a/src/server/net.c b/src/server/net.c
index f28fc25..e967d5c 100644
--- a/src/server/net.c
+++ b/src/server/net.c
@@ -116,7 +116,7 @@ static inline char send_reply(int sock, dnbd3_reply_t *reply, void *payload)
return 1;
}
-void *dnbd3_handle_query(void *dnbd3_client)
+void *net_client_handler(void *dnbd3_client)
{
dnbd3_client_t *client = (dnbd3_client_t *) (uintptr_t) dnbd3_client;
dnbd3_request_t request;
diff --git a/src/server/net.h b/src/server/net.h
index 9b163de..2c4115d 100644
--- a/src/server/net.h
+++ b/src/server/net.h
@@ -21,6 +21,6 @@
#ifndef NET_H_
#define NET_H_
-void *dnbd3_handle_query(void *client_socket);
+void *net_client_handler(void *client_socket);
#endif /* NET_H_ */
diff --git a/src/server/rpc.c b/src/server/rpc.c
deleted file mode 100644
index e253ace..0000000
--- a/src/server/rpc.c
+++ /dev/null
@@ -1,810 +0,0 @@
-/*
- * This file is part of the Distributed Network Block Device 3
- *
- * Copyright(c) 2011-2012 Johann Latocha <johann@latocha.de>
- *
- * This file may be licensed under the terms of of the
- * GNU General Public License Version 2 (the ``GPL'').
- *
- * Software distributed under the License is distributed
- * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
- * express or implied. See the GPL for the specific language
- * governing rights and limitations.
- *
- * You should have received a copy of the GPL along with this
- * program. If not, go to http://www.gnu.org/licenses/gpl.html
- * or write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "rpc.h"
-#include "../config.h"
-#include "server.h"
-#include "saveload.h"
-#include "memlog.h"
-#include "helper.h"
-
-#include <sys/un.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <grp.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-#include <pthread.h>
-#include <errno.h>
-#include "sockhelper.h"
-
-#include <libxml/parser.h>
-#include <libxml/xpath.h>
-#include "xmlutil.h"
-
-#define RPC_PORT (PORT+1)
-
-#define MAX_SERVER_SOCKETS 50 // Assume there will be no more than 50 sockets the server will listen on
-static int server_socks[MAX_SERVER_SOCKETS], server_count = 0;
-static volatile int keep_running = 1;
-static char *payload = NULL;
-
-#define char_repeat_br(_c, _times) do { \
- int _makro_i_ = (_times); \
- while (--_makro_i_ >= 0) putchar(_c); \
- putchar('\n'); \
-} while (0)
-
-static int rpc_receive(int client_sock);
-static int get_highest_fd(GSList *sockets);
-static int is_password_correct(xmlDocPtr doc);
-static int get_terminal_width();
-static int rpc_send_reply(int sock, dnbd3_rpc_t* header, int result_code, xmlDocPtr payload);
-
-static int get_highest_fd(GSList *sockets)
-{
- int max = 0;
-
- for (int i = 0; i < server_count; ++i)
- {
- if (server_socks[i] > max)
- max = server_socks[i];
- }
-
- for (GSList *iterator = sockets; iterator; iterator = iterator->next)
- {
- const int fd = (int)(size_t)iterator->data;
- if (fd > max)
- max = fd;
- }
- //printf("Max fd: %d\n", max);
- return max;
-}
-
-void *dnbd3_rpc_mainloop()
-{
-
- // Check version and initialize
- LIBXML_TEST_VERSION
-
- payload = malloc(MAX_RPC_PAYLOAD);
- if (payload == NULL)
- {
- memlogf("[CRITICAL] Couldn't allocate RPC payload buffer. RPC disabled.");
- pthread_exit((void *)0);
- return NULL;
- }
-
- struct sockaddr_storage client;
-
- sock_add_array(sock_listen_any(PF_INET, RPC_PORT), server_socks, &server_count, MAX_SERVER_SOCKETS);
-#ifdef WITH_IPV6
- sock_add_array(sock_listen_any(PF_INET6, RPC_PORT), server_socks, &server_count, MAX_SERVER_SOCKETS);
-#endif
-
- // Bind to socket
- if (server_count == 0)
- {
- perror("ERROR: RPC bind/listen unsuccessful");
- exit(EXIT_FAILURE);
- }
-
- // Run connection-accepting loop
-
- fd_set all_sockets, readset, exceptset;
-
- GSList *sockets = NULL, *iterator;
-
- int client_sock, ret;
- int maxfd = get_highest_fd(sockets);
- int error_count = 0;
-
- struct timeval select_timeout;
-
- FD_ZERO(&all_sockets);
- for (int i = 0; i < server_count; ++i)
- {
- FD_SET(server_socks[i], &all_sockets);
- sock_set_nonblock(server_socks[i]);
- }
-
- while (keep_running)
- {
- readset = exceptset = all_sockets;
- select_timeout.tv_sec = 4;
- select_timeout.tv_usec = 0;
- ret = select(maxfd, &readset, NULL, &exceptset, &select_timeout);
- while (ret > 0)
- {
- for (int i = 0; i < server_count; ++i)
- {
- if (FD_ISSET(server_socks[i], &readset))
- {
- --ret;
- // Accept connection
- socklen_t len = sizeof(client);
- if ((client_sock = accept(server_socks[i], (struct sockaddr *)&client, &len)) < 0)
- {
- if (errno != EAGAIN)
- {
- memlogf("[ERROR] Error accepting an RPC connection");
- if (++error_count > 10)
- goto end_loop;
- }
- continue;
- }
- error_count = 0;
- // Apply read/write timeout
- sock_set_timeout(client_sock, 500);
- // Make new connection blocking
- sock_set_block(client_sock);
- sockets = g_slist_prepend(sockets, (void *)(size_t)client_sock);
- if (client_sock >= maxfd)
- maxfd = client_sock + 1;
- //printf("Max fd: %d\n", (maxfd-1));
- FD_SET(client_sock, &all_sockets);
- }
- if (FD_ISSET(server_socks[i], &exceptset))
- {
- --ret;
- memlogf("[ERROR] An exception occurred on the RPC listening socket.");
- if (++error_count > 10)
- goto end_loop;
- }
- }
- if (ret > 0)
- {
- // Must be an active RPC connection
- int del = -1;
- for (iterator = sockets; iterator; iterator = iterator->next)
- {
- if (del != -1)
- {
- // Delete a previously closed connection from list (delayed, otherwise list might get messed up)
- sockets = g_slist_remove(sockets, (void *)(size_t)del);
- del = -1;
- maxfd = get_highest_fd(sockets) + 1;
- }
- client_sock = (int)(size_t)iterator->data;
- if (FD_ISSET(client_sock, &readset))
- {
- --ret;
- // Client sending data
- if (!rpc_receive(client_sock))
- {
- // Connection has been closed
- close(client_sock);
- del = client_sock;
- FD_CLR(client_sock, &all_sockets);
- }
- }
- if (FD_ISSET(client_sock, &exceptset))
- {
- --ret;
- // Something unexpected happened, just close connection
- close(client_sock);
- del = client_sock;
- FD_CLR(client_sock, &all_sockets);
- }
- }
- if (del != -1)
- {
- // In case last socket was closed during iteration
- sockets = g_slist_remove(sockets, (void *)(size_t)del);
- maxfd = get_highest_fd(sockets) + 1;
- }
- }
- } // End select loop
- } // End mainloop
-
-end_loop:
- memlogf("[INFO] Shutting down RPC interface.");
- dnbd3_rpc_shutdown();
-
- free(payload);
- xmlCleanupParser();
- pthread_exit((void *)0);
- return NULL;
-}
-
-void dnbd3_rpc_shutdown()
-{
- keep_running = 0;
- for (int i = 0; i < server_count; ++i)
- {
- if (server_socks[i] == -1)
- continue;
- close(server_socks[i]);
- server_socks[i] = -1;
- }
- server_count = 0;
-}
-
-/**
- * Returns !=0 if send/recv successful, 0 on any kind of network failure
- */
-static int rpc_receive(int client_sock)
-{
- GSList *iterator, *iterator2;
-
-#define STRBUFLEN 100
- char strbuffer[STRBUFLEN];
-
- dnbd3_rpc_t header;
-
- uint32_t cmd;
-
- int ret, locked = 0;
- int return_value = 0;
- xmlDocPtr docReply = NULL, docRequest = NULL;
- xmlNodePtr root_node, parent_node, tmp_node, log_parent_node, log_node, server_node;
-
- ret = recv(client_sock, &header, sizeof(header), MSG_WAITALL);
- if (ret != sizeof(header))
- return ((ret < 0 && errno == EAGAIN) ? 1 : 0);
- cmd = ntohl(header.cmd); // Leave header.cmd in network byte order for reply
- header.size = ntohl(header.size);
-
- int rpc_error = ERROR_UNSPECIFIED_ERROR; // Default value of error, so remember to set it for the reply if call succeeded
-
- if (header.size != 0)
- {
- // Message has payload, receive it
- if (header.size > MAX_RPC_PAYLOAD)
- {
- memlogf("[WARNING] RPC command with payload of %u bytes ignored.", (unsigned int)header.size);
- return 0;
- }
- if (!recv_data(client_sock, payload, header.size))
- return 0;
-
- docRequest = xmlReadMemory(payload, header.size, "noname.xml", NULL, 0);
- }
-
- switch (cmd)
- {
- case RPC_EXIT:
- memlogf("[INFO] Server shutdown by RPC request");
- header.size = ntohl(0);
- return_value = send_data(client_sock, &header, sizeof(header));
- dnbd3_cleanup();
- break;
-
- case RPC_IMG_LIST:
- if (!createXmlDoc(&docReply, &root_node, "data"))
- goto case_end;
-
- // Images
- parent_node = xmlNewNode(NULL, BAD_CAST "images");
- if (parent_node == NULL)
- goto case_end;
- xmlAddChild(root_node, parent_node);
- locked = 1;
- pthread_spin_lock(&_spinlock);
- for (iterator = _dnbd3_images; iterator; iterator = iterator->next)
- {
- const dnbd3_image_t *image = iterator->data;
- tmp_node = xmlNewNode(NULL, BAD_CAST "image");
- if (tmp_node == NULL)
- goto case_end;
- xmlNewProp(tmp_node, BAD_CAST "name", BAD_CAST image->low_name);
- xmlAddDecimalProp(image->rid, tmp_node, "rid");
- xmlAddDecimalProp(image->atime, tmp_node, "atime");
- xmlAddDecimalProp(image->delete_soft, tmp_node, "softdelete");
- xmlAddDecimalProp(image->delete_hard, tmp_node, "harddelete");
- xmlAddDecimalProp(image->filesize, tmp_node, "size");
- if (image->file)
- xmlNewProp(tmp_node, BAD_CAST "file", BAD_CAST image->file);
- if (image->cache_file && image->cache_map)
- {
- xmlNewProp(tmp_node, BAD_CAST "cachefile", BAD_CAST image->cache_file);
- int i, complete = 0, size = IMGSIZE_TO_MAPBYTES(image->filesize);
- for (i = 0; i < size; ++i)
- if (image->cache_map[i])
- complete += 100;
- xmlAddDecimalProp(complete / size, tmp_node, "cachefill");
- }
- // Build space separated list of alt servers
- int i;
- char serverstr[1000] = {0}, target[100];
- for (i = 0; i < NUMBER_SERVERS; ++i)
- {
- if (image->servers[i].host.type == 0) continue;
- if (!host_to_string(&(image->servers[i].host), target, 100)) continue;
- if (*serverstr) strcat(serverstr, " ");
- strcat(serverstr, target);
- }
- xmlNewProp(tmp_node, BAD_CAST "servers", BAD_CAST serverstr); // TODO
- xmlAddChild(parent_node, tmp_node);
- }
- pthread_spin_unlock(&_spinlock);
- locked = 0;
-
- // Dump and send
- rpc_error = 0;
- break;
-
- case RPC_CLIENT_LIST:
- if (!createXmlDoc(&docReply, &root_node, "data"))
- goto case_end;
-
- // Clients
- parent_node = xmlNewNode(NULL, BAD_CAST "clients");
- if (parent_node == NULL)
- goto case_end;
- xmlAddChild(root_node, parent_node);
- locked = 1;
- pthread_spin_lock(&_spinlock);
- for (iterator = _dnbd3_clients; iterator; iterator = iterator->next)
- {
- dnbd3_client_t *client = iterator->data;
- if (client->image)
- {
- tmp_node = xmlNewNode(NULL, BAD_CAST "client");
- if (tmp_node == NULL)
- goto case_end;
- host_to_string(&client->host, strbuffer, STRBUFLEN);
- xmlNewProp(tmp_node, BAD_CAST "address", BAD_CAST strbuffer);
- xmlNewProp(tmp_node, BAD_CAST "image", BAD_CAST client->image->low_name);
- xmlAddDecimalProp(client->image->rid, tmp_node, "rid");
- xmlAddChild(parent_node, tmp_node);
- }
- }
- pthread_spin_unlock(&_spinlock);
- locked = 0;
-
- // Dump and send
- rpc_error = 0;
- break;
-
- case RPC_TRUSTED_LIST:
- if (!createXmlDoc(&docReply, &root_node, "data"))
- goto case_end;
-
- // Trusted servers
- parent_node = xmlNewNode(NULL, BAD_CAST "trusted");
- if (parent_node == NULL)
- goto case_end;
- xmlAddChild(root_node, parent_node);
- locked = 1;
- pthread_spin_lock(&_spinlock);
- for (iterator = _trusted_servers; iterator; iterator = iterator->next)
- {
- dnbd3_trusted_server_t *server = iterator->data;
- if (server->host.type != 0)
- {
- tmp_node = xmlNewNode(NULL, BAD_CAST "server");
- if (tmp_node == NULL)
- goto case_end;
- xmlNodePtr namespace_root = xmlNewNode(NULL, BAD_CAST "namespaces");
- if (namespace_root == NULL)
- goto case_end;
- host_to_string(&server->host, strbuffer, STRBUFLEN);
- xmlNewProp(tmp_node, BAD_CAST "address", BAD_CAST strbuffer);
- if (server->comment)
- xmlNewProp(tmp_node, BAD_CAST "comment", BAD_CAST server->comment);
- for (iterator2 = server->namespaces; iterator2; iterator2 = iterator2->next)
- {
- const dnbd3_namespace_t *ns = iterator2->data;
- server_node = xmlNewNode(NULL, BAD_CAST "namespace");
- if (server_node == NULL)
- goto case_end;
- xmlAddChild(namespace_root, server_node);
- xmlNewProp(server_node, BAD_CAST "name", BAD_CAST ns->name);
- if (ns->auto_replicate)
- xmlNewProp(server_node, BAD_CAST "replicate", BAD_CAST "1");
- if (ns->recursive)
- xmlNewProp(server_node, BAD_CAST "recursive", BAD_CAST "1");
- }
- xmlAddChild(parent_node, tmp_node);
- xmlAddChild(tmp_node, namespace_root);
- }
- }
- pthread_spin_unlock(&_spinlock);
- locked = 0;
-
- // Dump and send
- rpc_error = 0;
- break;
-
- case RPC_GET_LOG:
- if (!createXmlDoc(&docReply, &root_node, "data"))
- goto case_end;
-
- // Log
- log_parent_node = xmlNewChild(root_node, NULL, BAD_CAST "log", NULL);
- if (log_parent_node == NULL)
- goto case_end;
- char *log = fetchlog(0);
- if (log == NULL)
- log = strdup("LOG IS NULL");
- log_node = xmlNewCDataBlock(docReply, BAD_CAST log, strlen(log));
- free(log);
- if (log_node == NULL)
- goto case_end;
- xmlAddChild(log_parent_node, log_node);
-
- // Dump and send
- rpc_error = 0;
- break;
-
- case RPC_ADD_IMG:
- case RPC_DEL_IMG:
- if (docRequest)
- {
- if (!is_password_correct(docRequest))
- {
- rpc_error = ERROR_WRONG_PASSWORD;
- break;
- }
-
- xmlNodePtr cur = NULL;
- int count = 0;
-
- FOR_EACH_NODE(docRequest, "/data/image", cur)
- {
- if (cur->type != XML_ELEMENT_NODE)
- continue;
- NEW_POINTERLIST;
- ++count;
- dnbd3_image_t image;
- memset(&image, 0, sizeof(dnbd3_image_t));
- image.config_group = XML_GETPROP(cur, "name");
- char *rid_str = XML_GETPROP(cur, "rid");
- image.file = XML_GETPROP(cur, "file");
- image.cache_file = XML_GETPROP(cur, "cache");
- if (image.file && !file_exists(image.file))
- {
- printf("Image File: %s\n", image.file);
- rpc_error = ERROR_FILE_NOT_FOUND;
- }
- else if (image.cache_file && !file_writable(image.cache_file))
- {
- rpc_error = ERROR_NOT_WRITABLE;
- }
- else
- {
- if (image.config_group && rid_str)
- {
- image.rid = atoi(rid_str);
- if (cmd == RPC_ADD_IMG)
- {
- rpc_error = dnbd3_add_image(&image);
- }
- else
- {
- char *soft = XML_GETPROP(cur, "softdelete");
- char *hard = XML_GETPROP(cur, "harddelete");
- image.delete_soft = time(NULL);
- image.delete_hard = time(NULL);
- if (soft) image.delete_soft += atoi(soft);
- if (hard) image.delete_hard += atoi(hard);
- rpc_error = dnbd3_del_image(&image);
- }
- }
- else
- rpc_error = ERROR_MISSING_ARGUMENT;
- }
- FREE_POINTERLIST;
- } END_FOR_EACH;
- if (count == 0)
- rpc_error = ERROR_MISSING_ARGUMENT;
- }
- else
- rpc_error = ERROR_INVALID_XML;
-
- break;
-
- case RPC_ADD_NS:
- case RPC_DEL_NS:
- if (docRequest)
- {
- if (!is_password_correct(docRequest))
- {
- rpc_error = ERROR_WRONG_PASSWORD;
- break;
- }
-
- xmlNodePtr cur = NULL;
-
- FOR_EACH_NODE(docRequest, "/data/namespaces/namespace", cur)
- {
- if (cur->type != XML_ELEMENT_NODE)
- continue;
- NEW_POINTERLIST;
- char *host = XML_GETPROP(cur, "address");
- char *ns = XML_GETPROP(cur, "name");
- char *flags = XML_GETPROP(cur, "flags");
- char *comment = XML_GETPROP(cur, "comment");
- pthread_spin_lock(&_spinlock);
- if (host && ns)
- {
- if (cmd == RPC_ADD_NS)
- {
- dnbd3_trusted_server_t *server = dnbd3_get_trusted_server(host, TRUE, comment);
- if (server && dnbd3_add_trusted_namespace(server, ns, flags))
- rpc_error = ERROR_OK;
- else
- rpc_error = ERROR_UNSPECIFIED_ERROR;
- }
- else
- {
- dnbd3_trusted_server_t *server = dnbd3_get_trusted_server(host, FALSE, comment);
- if (server && dnbd3_del_trusted_namespace(server, ns))
- rpc_error = ERROR_OK;
- else
- rpc_error = ERROR_FILE_NOT_FOUND;
- }
- }
- pthread_spin_unlock(&_spinlock);
- FREE_POINTERLIST;
- } END_FOR_EACH;
- if (rpc_error == ERROR_OK) dnbd3_save_config();
- }
- else
- rpc_error = ERROR_INVALID_XML;
-
- break;
-
- default:
- memlogf("[ERROR] Unknown RPC command: %u", (unsigned int)header.cmd);
- rpc_error = ERROR_UNKNOWN_COMMAND;
- break;
-
- }
-case_end:
-
- if (locked)
- pthread_spin_unlock(&_spinlock);
- // Send reply
- return_value = rpc_send_reply(client_sock, &header, rpc_error, docReply);
-
- xmlFreeDoc(docReply);
- xmlFreeDoc(docRequest);
-
- return return_value;
-}
-
-void dnbd3_rpc_send(int cmd)
-{
- int client_sock, size;
-
- // Check version and initialize
- LIBXML_TEST_VERSION
-
- struct sockaddr_in server;
-
- memset(&server, 0, sizeof(server));
- server.sin_family = AF_INET; // IPv4
- server.sin_addr.s_addr = inet_addr("127.0.0.1");
- server.sin_port = htons(RPC_PORT); // set port number
-
- // Connect to server
- if ((client_sock = sock_connect4(&server, 2000, 1000)) == -1)
- {
- perror("ERROR: RPC connect");
- exit(EXIT_FAILURE);
- }
-
- // Send message
- dnbd3_rpc_t header;
- header.cmd = htonl(cmd);
- header.size = 0;
- send(client_sock, (char *)&header, sizeof(header), MSG_WAITALL);
- recv(client_sock, &header, sizeof(header), MSG_WAITALL);
- header.cmd = ntohl(header.cmd);
- header.size = ntohl(header.size);
-
- if (cmd == RPC_IMG_LIST && header.size > 0)
- {
- char *buf = malloc(header.size + 1);
- size = recv(client_sock, buf, header.size, MSG_WAITALL);
- printf("\n%s\n\n", buf);
- xmlDocPtr doc = xmlReadMemory(buf, size, "noname.xml", NULL, 0);
- buf[header.size] = 0;
-
- if (doc)
- {
- int count;
- int term_width = get_terminal_width();
- xmlNodePtr cur, childit;
-
- // Print log
- char *log = getTextFromPath(doc, "/data/log");
- if (log)
- {
- printf("--- Last log lines ----\n%s\n\n", log);
- xmlFree(log);
- }
-
- int watime = 17, wname = 0, wrid = 5;
- FOR_EACH_NODE(doc, "/data/images/image", cur)
- {
- if (cur->type != XML_ELEMENT_NODE)
- continue;
- NEW_POINTERLIST; // This macro defines an array of pointers
- char *vid = XML_GETPROP(cur, "name"); // XML_GETPROP is a macro wrapping xmlGetNoNsProp()
- char *rid = XML_GETPROP(cur, "rid"); // Each of these calls allocates memory for the string
- wname = MAX(wname, strlen(vid));
- wrid = MAX(wrid, strlen(rid));
- FREE_POINTERLIST; // This macro simply frees all pointers in the above array
- } END_FOR_EACH;
-
- char format[100], strbuffer[STRBUFLEN];
- snprintf(format, 100,
- "%%-%ds %%-%ds %%%ds %%s\n", watime, wname, wrid);
-
- // Print images
- printf("Exported images\n");
- printf(format, "atime", "name", "rid", "file");
- char_repeat_br('=', term_width);
- count = 0;
- FOR_EACH_NODE(doc, "/data/images/image", cur)
- {
- if (cur->type != XML_ELEMENT_NODE)
- continue;
- NEW_POINTERLIST;
- ++count;
- char *numatime = XML_GETPROP(cur, "atime");
- char *vid = XML_GETPROP(cur, "name");
- char *rid = XML_GETPROP(cur, "rid");
- char *file = XML_GETPROP(cur, "file");
- time_t at = (time_t)atol(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);
-
- // Print clients
- printf("Connected clients (ip, file):\n");
- char_repeat_br('=', term_width);
- count = 0;
- FOR_EACH_NODE(doc, "/data/clients/client", cur)
- {
- if (cur->type != XML_ELEMENT_NODE)
- continue;
- ++count;
- xmlChar *ip = xmlGetNoNsProp(cur, BAD_CAST "ip");
- 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;
- char_repeat_br('=', term_width);
- printf("\nNumber clients: %d\n\n", count);
-
- // Print trusted servers
- printf("Trusted servers:\n");
- char_repeat_br('=', term_width);
- count = 0;
- FOR_EACH_NODE(doc, "/data/trusted/server", cur)
- {
- if (cur->type != XML_ELEMENT_NODE)
- continue;
- NEW_POINTERLIST;
- ++count;
- char *address = XML_GETPROP(cur, "address");
- char *comment = XML_GETPROP(cur, "comment");
- if (comment)
- printf("%-30s (%s)\n", address, comment);
- else
- printf("%-30s\n", address);
- for (childit = cur->children; childit; childit = childit->next)
- {
- if (childit->type != XML_ELEMENT_NODE || childit->name == NULL || strcmp((const char*)childit->name, "namespace") != 0)
- continue;
- NEW_POINTERLIST;
- char *name = XML_GETPROP(childit, "name");
- char *replicate = XML_GETPROP(childit, "replicate");
- char *recursive = XML_GETPROP(childit, "recursive");
- printf(" %-40s ", name);
- if (replicate && *replicate != '0')
- printf(" replicate");
- if (recursive && *recursive != '0')
- printf(" recursive");
- putchar('\n');
- FREE_POINTERLIST;
- }
- FREE_POINTERLIST;
- } END_FOR_EACH;
- char_repeat_br('=', term_width);
- printf("\nNumber servers: %d\n\n", count);
-
- // Cleanup
- xmlFreeDoc(doc);
- xmlCleanupParser();
-
-// xmlDocDump(stdout, doc);
-
- }
- else
- {
- printf("ERROR: Failed to parse reply\n-----------\n%s\n-------------\n", buf);
- }
-
- }
-
- close(client_sock);
-}
-
-/**
- * Check if the correct server password is present in xpath /data/password
- * return !=0 if correct, 0 otherwise
- */
-static int is_password_correct(xmlDocPtr doc)
-{
- if (_rpc_password == NULL)
- {
- memlogf("[WARNING] RPC access granted as no password is set!");
- return 1;
- }
- char *pass = getTextFromPath(doc, "/data/password");
- if (pass == NULL)
- return 0;
- if (strcmp(pass, _rpc_password) == 0)
- {
- xmlFree(pass);
- return 1;
- }
- xmlFree(pass);
- return 0;
-}
-
-static int get_terminal_width()
-{
- struct winsize w;
- if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) < 0)
- return 80;
- return w.ws_col;
-}
-
-#define RETBUFLEN 8000
-static char returnbuffer[RETBUFLEN];
-static int rpc_send_reply(int sock, dnbd3_rpc_t* header, int result_code, xmlDocPtr payload)
-{
- if (result_code == 0 && payload != NULL)
- {
- // No error
- xmlChar *xmlbuff = NULL;
- int buffersize;
- xmlDocDumpFormatMemory(payload, &xmlbuff, &buffersize, 1);
- header->size = htonl(buffersize);
- if (!send_data(sock, header, sizeof(*header)))
- return FALSE;
- if (xmlbuff)
- return send_data(sock, xmlbuff, buffersize);
- return TRUE;
- }
- // Error code, build xml struct (lazy shortcut)
- int len = snprintf(returnbuffer, RETBUFLEN, "<?xml version=\"1.0\"?>\n"
- "<data>\n"
- "<result retcode=\"%d\" retstr=\"%s\" />\n"
- "</data>", result_code, "TODO");
- if (len >= RETBUFLEN)
- len = 10;
- header->size = htonl(len);
- header->cmd = htonl(RPC_ERROR);
- if (!send_data(sock, header, sizeof(*header)))
- return FALSE;
- return send_data(sock, returnbuffer, len);
-}
diff --git a/src/server/rpc.h b/src/server/rpc.h
deleted file mode 100644
index a7c9f39..0000000
--- a/src/server/rpc.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * This file is part of the Distributed Network Block Device 3
- *
- * Copyright(c) 2011-2012 Johann Latocha <johann@latocha.de>
- *
- * This file may be licensed under the terms of of the
- * GNU General Public License Version 2 (the ``GPL'').
- *
- * Software distributed under the License is distributed
- * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
- * express or implied. See the GPL for the specific language
- * governing rights and limitations.
- *
- * You should have received a copy of the GPL along with this
- * program. If not, go to http://www.gnu.org/licenses/gpl.html
- * or write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef RPC_H_
-#define RPC_H_
-
-#include <stdint.h>
-
-#define RPC_EXIT 0
-#define RPC_RELOAD 1
-#define RPC_IMG_LIST 2
-#define RPC_ADD_IMG 3
-#define RPC_DEL_IMG 4
-#define RPC_ADD_NS 5
-#define RPC_DEL_NS 6
-#define RPC_CLIENT_LIST 7
-#define RPC_TRUSTED_LIST 8
-#define RPC_GET_LOG 9
-#define RPC_FIX_IMAGE 10
-#define RPC_ERROR 11
-
-void *dnbd3_rpc_mainloop();
-
-void dnbd3_rpc_shutdown();
-
-void dnbd3_rpc_send(int cmd);
-
-
-#pragma pack(1)
-typedef struct
-{
- uint32_t handle;// 4byte
- uint32_t cmd; // 4byte
- uint32_t size; // 4byte
-} dnbd3_rpc_t;
-#pragma pack(0)
-
-#endif /* RPC_H_ */
diff --git a/src/server/saveload.c b/src/server/saveload.c
deleted file mode 100644
index e888f50..0000000
--- a/src/server/saveload.c
+++ /dev/null
@@ -1,734 +0,0 @@
-/*
- * This file is part of the Distributed Network Block Device 3
- *
- * Copyright(c) 2011-2012 Johann Latocha <johann@latocha.de>
- *
- * This file may be licensed under the terms of of the
- * GNU General Public License Version 2 (the ``GPL'').
- *
- * Software distributed under the License is distributed
- * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
- * express or implied. See the GPL for the specific language
- * governing rights and limitations.
- *
- * You should have received a copy of the GPL along with this
- * program. If not, go to http://www.gnu.org/licenses/gpl.html
- * or write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <pthread.h>
-#include <string.h>
-#include <glib.h>
-#include <math.h>
-#include <netinet/in.h>
-
-#include "server.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 dnbd3_image_t *prepare_image(char *image_name, int rid, char *image_file, char *cache_file);
-
-
-void dnbd3_load_config()
-{
- gint i, j;
-
- if (_config_handle != NULL)
- {
- printf("dnbd3_load_config() called more than once\n\n");
- exit(EXIT_FAILURE);
- }
-
- _config_handle = g_key_file_new();
- if (!g_key_file_load_from_file(_config_handle, _config_file_name, G_KEY_FILE_NONE, NULL))
- {
- printf("ERROR: Config file not found: %s\n", _config_file_name);
- exit(EXIT_FAILURE);
- }
-
- srand(time(NULL));
-
- _rpc_password = g_key_file_get_string(_config_handle, "settings", "password", NULL);
- _cache_dir = g_key_file_get_string(_config_handle, "settings", "cache_dir", NULL);
-
- if (_cache_dir == NULL)
- memlogf("[WARNING] No cache dir set! Automatic replication will not work.");
- else if (access(_cache_dir, R_OK | W_OK) != 0)
- memlogf("[WARNING] Cache dir '%s' is not readable or writable", _cache_dir);
-
- gchar **groups = NULL;
- gsize section_count;
- groups = g_key_file_get_groups(_config_handle, &section_count);
-
- for (i = 0; i < section_count; i++)
- {
- // Ignore settings section
- if (strcmp(groups[i], "settings") == 0)
- continue;
-
- // List of trusted servers/namespaces
- if (strncmp(groups[i], "trust:", 6) == 0)
- {
- 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, groups[i]+6);
- g_free(addr);
- if (server == NULL)
- continue;
- gsize key_count;
- gchar **keys = g_key_file_get_keys(_config_handle, groups[i], &key_count, NULL);
- for (j = 0; j < key_count; ++j)
- {
- if (strcmp(keys[j], "address") == 0)
- continue;
- char *flags = g_key_file_get_string(_config_handle, groups[i], keys[j], NULL);
- g_key_file_remove_key(_config_handle, groups[i], keys[j], NULL);
- dnbd3_add_trusted_namespace(server, keys[j], flags);
- g_free(flags);
- }
- g_strfreev(keys);
- continue;
- }
-
- // An actual image definition
-
- int rid = g_key_file_get_integer(_config_handle, groups[i], "rid", NULL);
- if (rid <= 0)
- {
- memlogf("[ERROR] Invalid rid '%d' for image '%s'", rid, groups[i]);
- continue;
- }
-
- const time_t delsoft = g_key_file_get_int64(_config_handle, groups[i], "delete_soft", NULL);
- const time_t delhard = g_key_file_get_int64(_config_handle, groups[i], "delete_hard", NULL);
- if ((delsoft != 0 && delsoft < time(NULL)) || (delhard != 0 && delhard < time(NULL)))
- {
- memlogf("[INFO] Ignoring image '%s' as its deletion is due", groups[i]);
- continue;
- }
-
- 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);
-
- dnbd3_image_t *image = prepare_image(groups[i], rid, image_file, cache_file);
- if (image)
- {
- _dnbd3_images = g_slist_prepend(_dnbd3_images, image);
- }
-
- g_free(image_file);
- g_free(cache_file);
- }
-
- g_strfreev(groups);
-}
-
-int dnbd3_add_image(dnbd3_image_t *image)
-{
- if (image->file)
- {
- if (strncmp(image->file, "/dev/dnbd", 9) == 0)
- return ERROR_IMAGE_NOT_FOUND;
- int fh = open(image->file, O_RDONLY);
- if (fh < 0)
- return ERROR_IMAGE_NOT_FOUND;
- close(fh);
- }
- // Lock here to prevent concurrent add calls to mess rids up. Cannot happen currently
- // as RPC clients are not threaded and they're the only place where this is called,
- // but better be safe for the future...
- pthread_spin_lock(&_spinlock);
- if (image->rid == 0)
- {
- const dnbd3_image_t *latest = dnbd3_get_image(image->config_group, 0, 0);
- if (latest)
- image->rid = latest->rid + 1;
- else
- image->rid = 1;
- }
-
- dnbd3_image_t *newimage = prepare_image(image->config_group, image->rid, image->file, image->cache_file);
- if (newimage)
- {
- if (image->file == NULL && newimage->filesize == 0)
- newimage->filesize = image->filesize;
- _dnbd3_images = g_slist_prepend(_dnbd3_images, newimage);
- }
- else
- {
- pthread_spin_unlock(&_spinlock);
- return ERROR_SEE_LOG;
- }
- image = NULL;
-
- // Adding image was successful, write config file
- g_key_file_set_integer(_config_handle, newimage->config_group, "rid", newimage->rid);
- if (newimage->file)
- g_key_file_set_string(_config_handle, newimage->config_group, "file", newimage->file);
- if (newimage->cache_file)
- g_key_file_set_string(_config_handle, newimage->config_group, "cache", newimage->cache_file);
-
- pthread_spin_unlock(&_spinlock);
-
- const int ret = dnbd3_save_config();
- if (ret == ERROR_OK)
- memlogf("[INFO] Added new image '%s' (rid %d)", newimage->config_group, newimage->rid);
- else
- memlogf("[INFO] Added new image '%s' (rid %d), but config file could not be written (%s)", newimage->config_group, newimage->rid, _config_file_name);
- return ret;
-}
-
-int dnbd3_del_image(dnbd3_image_t *image)
-{
- if (image->rid <= 0) // Require a specific rid on deletion
- return ERROR_RID;
- pthread_spin_lock(&_spinlock);
- dnbd3_image_t *existing_image = dnbd3_get_image(image->config_group, image->rid, 0);
- if(existing_image == NULL)
- {
- pthread_spin_unlock(&_spinlock);
- return ERROR_IMAGE_NOT_FOUND;
- }
-
- existing_image->delete_soft = image->delete_soft;
- existing_image->delete_hard = image->delete_hard;
- g_key_file_set_int64(_config_handle, image->config_group, "delete_soft", existing_image->delete_soft);
- g_key_file_set_int64(_config_handle, image->config_group, "delete_hard", existing_image->delete_hard);
-
- pthread_spin_unlock(&_spinlock);
- dnbd3_exec_delete(FALSE);
- existing_image = NULL;
-
- const int ret = dnbd3_save_config();
- if (ret == ERROR_OK)
- memlogf("[INFO] Marked for deletion: '%s' (rid %d)", image->config_group, image->rid);
- else
- memlogf("[WARNING] Marked for deletion: '%s' (rid %d), but config file could not be written (%s)", image->config_group, image->rid, _config_file_name);
- return ret;
-}
-
-int dnbd3_save_config()
-{
- pthread_spin_lock(&_spinlock);
- char *data = (char *)g_key_file_to_data(_config_handle, NULL, NULL);
- if (data == NULL)
- {
- pthread_spin_unlock(&_spinlock);
- memlogf("[ERROR] g_key_file_to_data() failed");
- return ERROR_UNSPECIFIED_ERROR;
- }
-
- FILE *f = fopen(_config_file_name, "w");
- if (f < 0)
- {
- pthread_spin_unlock(&_spinlock);
- g_free(data);
- return ERROR_CONFIG_FILE_PERMISSIONS;
- }
- fputs("# Do not edit this file while dnbd3-server is running\n", f);
- fputs(data, f);
- fclose(f);
- pthread_spin_unlock(&_spinlock);
- g_free(data);
- return 0;
-}
-
-dnbd3_image_t *dnbd3_get_image(char *name_orig, int rid, const char do_lock)
-{
- dnbd3_image_t *result = NULL, *image;
- GSList *iterator;
- // For comparison, make sure the name is global and lowercased
- char name[strlen(name_orig) + 1];
- strcpy(name, name_orig);
- strtolower(name);
- // Now find the image
- if (do_lock)
- pthread_spin_lock(&_spinlock);
- for (iterator = _dnbd3_images; iterator; iterator = iterator->next)
- {
- image = iterator->data;
- if (rid != 0) // rid was specified
- {
- if (image->rid == rid && strcmp(name, image->low_name) == 0)
- {
- result = image;
- break;
- }
- }
- else // search max. rid available
- {
- if (strcmp(name, image->low_name) == 0 && (result == NULL || result->rid < image->rid))
- {
- result = image;
- }
- }
- }
- if (do_lock)
- pthread_spin_unlock(&_spinlock);
- return result;
-}
-
-void dnbd3_handle_sigpipe(int signum)
-{
- memlogf("ERROR: SIGPIPE received (%s)", strsignal(signum));
-}
-
-void dnbd3_handle_sigterm(int signum)
-{
- memlogf("INFO: SIGTERM or SIGINT received (%s)", strsignal(signum));
- dnbd3_cleanup();
-}
-
-/**
- * Prepare image to be added to image list. Returns a pointer to a newly allocated image struct
- * on success, NULL otherwise.
- * 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)
-{
- int j;
- if (image_name == NULL)
- {
- memlogf("[ERROR] Null Image-Name");
- return NULL;
- }
-
- char *slash = strrchr(image_name, '/');
-
- if (slash == NULL)
- {
- memlogf("[ERROR] Invalid image name: '%s'", image_name);
- return NULL;
- }
- else
- {
- *slash = '\0';
- if (!is_valid_imagename(slash+1))
- {
- memlogf("[ERROR] Invalid image name: '%s'", slash+1);
- return NULL;
- }
- if (!is_valid_namespace(image_name))
- {
- memlogf("[ERROR] Invalid namespace: '%s'", image_name);
- *slash = '/';
- return NULL;
- }
- *slash = '/';
- }
-
- // Allocate image struct and zero it out by using g_new0
- dnbd3_image_t *image = g_new0(dnbd3_image_t, 1);
- if (image == NULL)
- {
- memlogf("[ERROR] Could not allocate dnbd3_image_t while reading config");
- return NULL;
- }
-
- image->low_name = strdup(image_name);
-
- strtolower(image->low_name);
- memlogf("[INFO] Loading image '%s'", image->low_name);
-
- if (dnbd3_get_image(image->low_name, rid, 0))
- {
- memlogf("[ERROR] Duplicate image in config: '%s' rid:%d", image_name, rid);
- goto error;
- }
-
- image->config_group = strdup(image_name);
-
- image->rid = rid;
- image->relayed = (image_file == NULL || image_file == '\0');
-
- if (image_file && strncmp(image_file, "/dev/dnbd", 9) == 0)
- {
- printf("[BUG BUG BUG] Image file is %s\n", image_file);
- image->relayed = TRUE;
- }
-
- if (image->relayed) // Image is relayed (this server acts as proxy)
- {
- if (strchr(image_name, '/') == NULL)
- {
- memlogf("[ERROR] Relayed image without global name in config: '%s'", image_name);
- goto error;
- }
- if (cache_file && *cache_file)
- image->cache_file = strdup(cache_file);
- }
- else // Image is a local one, open file to get size
- {
- image->file = strdup(image_file);
- int fd = open(image->file, O_RDONLY);
- if (fd < 0)
- {
- memlogf("[ERROR] Image file not found: '%s'", image->file);
- goto error;
- }
- const off_t size = lseek(fd, 0, SEEK_END);
- if (size <= 0)
- {
- memlogf("[ERROR] File '%s' of image '%s' has size '%lld'. Image ignored.",
- image->file, image_name, (long long)size);
- goto error;
- }
- image->filesize = (uint64_t)size;
- if (image->filesize & 4095)
- {
- memlogf("[WARNING] Size of image '%s' is not a multiple of 4096. Last incomplete block will be ignored!",
- image->file);
- image->filesize &= ~(uint64_t)4095;
- }
- close(fd);
- image->working = 1;
- }
-
- if (image->cache_file)
- {
- // Determine size of cached image
- int fd = open(image->cache_file, O_RDONLY);
- if (fd >= 0)
- {
- const off_t size = lseek(fd, 0, SEEK_END);
- if (size > 0)
- image->filesize = (uint64_t)size;
- close(fd);
- }
- if (image->filesize & 4095)
- {
- // Cache files should always be truncated to 4kib boundaries already
- memlogf("[WARNING] Size of cache file '%s' is not a multiple of 4096. Something's fishy!", image->cache_file);
- image->filesize = 0;
- }
- else if (image->filesize > 0)
- {
- printf("[DEBUG] Size known %llu for %s\n", (unsigned long long)image->filesize, image->cache_file);
- const size_t map_len_bytes = IMGSIZE_TO_MAPBYTES(image->filesize);
- image->cache_map = calloc(map_len_bytes, sizeof(uint8_t));
- // read cache map from file
- char tmp[strlen(image->cache_file) + 5];
- strcpy(tmp, image->cache_file);
- strcat(tmp, ".map");
- fd = open(tmp, O_RDONLY);
- if (fd >= 0)
- {
- const off_t size = lseek(fd, 0, SEEK_END);
- if (size != map_len_bytes)
- {
- memlogf("[DEBUG] Cache-Map of %s is corrupted (%d != %d)", image_name, (int)size, (int)map_len_bytes);
- }
- else
- {
- lseek(fd, 0, SEEK_SET);
- read(fd, image->cache_map, map_len_bytes);
- // If the whole image is cached, mark it as working right away without waiting for an upstream server
- image->working = 1;
- for (j = 0; j < map_len_bytes - 1; ++j)
- {
- if (image->cache_map[j] != 0xFF)
- {
- image->working = 0;
- break;
- }
- }
- const int blocks_in_last_byte = (image->filesize >> 12) & 7;
- uint8_t last_byte = 0;
- if (blocks_in_last_byte == 0)
- last_byte = 0xFF;
- else
- for (j = 0; j < blocks_in_last_byte; ++j)
- last_byte |= (1 << j);
- if ((image->cache_map[map_len_bytes - 1] & last_byte) != last_byte)
- image->working = 0;
- else
- memlogf("[INFO] Instantly publishing relayed image '%s' because the local cache copy is complete", image_name);
- }
- close(fd);
- }
- }
- } // end cache_file handling
- return image;
-error:
- // Free stuff. Some pointers might be zero, but calling free() on those is safe.
- free(image->cache_map);
- free(image->config_group);
- free(image->low_name);
- free(image->file);
- free(image->cache_file);
- g_free(image);
- return NULL;
-}
-
-/**
- * Iterate over all images and delete them if appropriate.
- */
-void dnbd3_exec_delete(int save_if_changed)
-{
- int changed = FALSE;
- const time_t now = time(NULL);
- GSList *image_iterator, *client_iterator;
- char ipstr[100];
- printf("[DEBUG] Scanning for deletable images\n");
-
- pthread_spin_lock(&_spinlock);
- for (image_iterator = _dnbd3_images; image_iterator; image_iterator = image_iterator->next)
- {
- dnbd3_image_t *image = image_iterator->data;
- int delete_now = TRUE;
- if (image->delete_hard != 0 && image->delete_hard < now)
- {
- printf("[DEBUG] HARD %s\n", image->low_name);
- // Drop all clients still using it
- for (client_iterator = _dnbd3_clients; client_iterator; client_iterator = client_iterator->next)
- {
- dnbd3_client_t *client = client_iterator->data;
- if (client->image != image)
- continue;
- // Kill client's connection
- *ipstr = '\0';
- 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;
- close(fd);
- 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 && image->atime + 3600 < now)
- {
- printf("[DEBUG] SOFT %s\n", image->low_name);
- // Image should be soft-deleted
- // Check if it is still in use
- for (client_iterator = _dnbd3_clients; client_iterator; client_iterator = client_iterator->next)
- {
- const dnbd3_client_t *client = client_iterator->data;
- if (client->image == image)
- {
- // Yep, still in use, keep it
- delete_now = FALSE;
- break;
- }
- }
- }
- else // Neither hard nor soft delete, keep it
- {
- delete_now = FALSE;
- }
- if (delete_now)
- {
- // Image was not in use and should be deleted, free it!
- memlogf("[INFO] Freeing end-of-life image %s", image->config_group);
- changed = TRUE;
- _dnbd3_images = g_slist_remove(_dnbd3_images, image); // Remove from image list
- g_key_file_remove_group(_config_handle, image->config_group, NULL); // Also remove from config file
- // Free any allocated memory
- free(image->cache_map);
- free(image->config_group);
- free(image->low_name);
- free(image->file);
- free(image->cache_file);
- g_free(image);
- // Restart iteration as it would be messed up now
- image_iterator = _dnbd3_images;
- if (image_iterator == NULL)
- break;
- }
- } // END image iteration
- pthread_spin_unlock(&_spinlock);
-
- if (changed && save_if_changed)
- dnbd3_save_config();
-}
-
-/**
- * Return pointer to trusted_server matching given address.
- * If not found and create_if_not_found is TRUE, a new entry will be created,
- * added to the list and then returned
- * 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, char *comment)
-{
- dnbd3_trusted_server_t server;
- memset(&server, 0, sizeof(server));
- if (!parse_address(address, &server.host))
- {
- memlogf("[WARNING] Could not parse address '%s' of trusted server", address);
- return NULL;
- }
-#ifndef WITH_IPV6
- if (server.host.type == AF_INET6)
- {
- printf("[DEBUG] Ignoring IPv6 trusted server.\n");
- return NULL;
- }
-#endif
- GSList *iterator;
- for (iterator = _trusted_servers; iterator; iterator = iterator->next)
- {
- dnbd3_trusted_server_t *comp = iterator->data;
- if (is_same_server(&comp->host, &server.host))
- return comp;
- }
- 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);
- dnbd3_trusted_server_t *copy = malloc(sizeof(server));
- memcpy(copy, &server, sizeof(*copy));
- copy->comment = strdup(groupname+6);
- _trusted_servers = g_slist_prepend(_trusted_servers, copy);
- free(groupname);
- return copy;
-}
-
-/**
- * Add new trusted namespace to given trusted server, using given flags.
- * Overwrites any existing entry for the given server and namespace
- * !! Lock before calling this function !!
- */
-int dnbd3_add_trusted_namespace(dnbd3_trusted_server_t *server, char *namespace, char *flags)
-{
- int nslen = strlen(namespace) + 1;
- char nslow[nslen];
- memcpy(nslow, namespace, nslen);
- remove_trailing_slash(nslow);
- strtolower(nslow);
- GSList *iterator;
- dnbd3_namespace_t *ns = NULL;
- for (iterator = server->namespaces; iterator; iterator = iterator->next)
- {
- dnbd3_namespace_t *cmp = iterator->data;
- if (strcmp(nslow, cmp->name) == 0)
- {
- ns = cmp;
- break;
- }
- }
- if (ns == NULL)
- {
- ns = calloc(1, sizeof(*ns));
- ns->name = strdup(nslow);
- server->namespaces = g_slist_prepend(server->namespaces, ns);
- }
- ns->auto_replicate = (flags && strstr(flags, "replicate"));
- ns->recursive = (flags && strstr(flags, "recursive"));
- size_t len = strlen(server->comment) + 7;
- char groupname[len];
- snprintf(groupname, len, "trust:%s", server->comment);
- if (ns->auto_replicate && ns->recursive)
- g_key_file_set_string(_config_handle, groupname, ns->name, "replicate,recursive");
- else if (ns->auto_replicate)
- g_key_file_set_string(_config_handle, groupname, ns->name, "replicate");
- else if (ns->recursive)
- g_key_file_set_string(_config_handle, groupname, ns->name, "recursive");
- else
- g_key_file_set_string(_config_handle, groupname, ns->name, "-");
- return TRUE;
-}
-
-/**
- * Remove trusted namespace from given trusted server.
- * !! Lock before calling this function !!
- * @return TRUE if element could be removed
- * !! Assume that the _trusted_servers list changed after calling this,
- * since the trusted server gets removed from it if this was the last namespace
- * it contained
- */
-int dnbd3_del_trusted_namespace(dnbd3_trusted_server_t *server, char *namespace)
-{
- int nslen = strlen(namespace) + 1;
- char nslow[nslen];
- memcpy(nslow, namespace, nslen);
- remove_trailing_slash(nslow);
- strtolower(nslow);
- GSList *iterator;
- for (iterator = server->namespaces; iterator; iterator = iterator->next)
- {
- dnbd3_namespace_t *cmp = iterator->data;
- if (strcmp(nslow, cmp->name) == 0)
- {
- // TODO: Remove from config file
- free(cmp->name);
- free(cmp);
- server->namespaces = g_slist_remove(server->namespaces, cmp);
- if (server->namespaces == NULL)
- {
- g_free(server->comment);
- _trusted_servers = g_slist_remove(_trusted_servers, server);
- free(server);
- }
- return TRUE;
- }
- }
- return FALSE;
-}
-
-/**
- * Gives the closest match of a namespace rule that can be applied to
- * the given namespace
- * Returns NULL if none
- * !! Lock before calling this function !!
- */
-dnbd3_namespace_t *dnbd3_get_trust_level(dnbd3_host_t *host, char *namespace)
-{
- dnbd3_trusted_server_t *server = NULL;
- GSList *iterator;
- for (iterator = _trusted_servers; iterator; iterator = iterator->next)
- {
- dnbd3_trusted_server_t *comp = iterator->data;
- if (!is_same_server(host, &comp->host))
- continue;
- server = comp;
- break;
- }
- if (server == NULL)
- return NULL;
- dnbd3_namespace_t *best = NULL;
- int bestlen = 0;
- char nslow[strlen(namespace)+1];
- strcpy(nslow, namespace);
- remove_trailing_slash(nslow);
- strtolower(nslow);
- for (iterator = server->namespaces; iterator; iterator = iterator-> next)
- {
- dnbd3_namespace_t *comp = iterator->data;
- const int cmplen = strlen(comp->name);
- if (strncmp(nslow, comp->name, cmplen) != 0) // names do not match at all
- continue;
- if (nslow[cmplen] == '/' && !comp->recursive) // partial match, but recursion is disabled
- continue;
- if (nslow[cmplen] != '\0' && nslow[cmplen] != '/') // in mid-string
- continue;
- if (cmplen < bestlen) // Match is not better than one found before
- continue;
- bestlen = cmplen;
- best = comp;
- }
- return best;
-}
diff --git a/src/server/saveload.h b/src/server/saveload.h
deleted file mode 100644
index 77528e4..0000000
--- a/src/server/saveload.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * This file is part of the Distributed Network Block Device 3
- *
- * Copyright(c) 2011-2012 Johann Latocha <johann@latocha.de>
- *
- * This file may be licensed under the terms of of the
- * GNU General Public License Version 2 (the ``GPL'').
- *
- * Software distributed under the License is distributed
- * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
- * express or implied. See the GPL for the specific language
- * governing rights and limitations.
- *
- * You should have received a copy of the GPL along with this
- * program. If not, go to http://www.gnu.org/licenses/gpl.html
- * or write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include <unistd.h>
-#include <sys/types.h>
-
-#include "server.h"
-#include "../config.h"
-
-#ifndef UTILS_H_
-#define UTILS_H_
-
-#define ERROR_OK 0
-#define ERROR_FILE_NOT_FOUND 1
-#define ERROR_IMAGE_ALREADY_EXISTS 2
-#define ERROR_CONFIG_FILE_PERMISSIONS 3
-#define ERROR_IMAGE_NOT_FOUND 4
-#define ERROR_RID 5
-#define ERROR_IMAGE_IN_USE 6
-#define ERROR_MISSING_ARGUMENT 7
-#define ERROR_UNSPECIFIED_ERROR 8
-#define ERROR_INVALID_XML 9
-#define ERROR_UNKNOWN_COMMAND 10
-#define ERROR_SEE_LOG 11
-#define ERROR_WRONG_PASSWORD 12
-#define ERROR_NOT_WRITABLE 13
-
-void dnbd3_load_config();
-int dnbd3_save_config();
-
-int dnbd3_add_image(dnbd3_image_t *image);
-int dnbd3_del_image(dnbd3_image_t *image);
-
-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, char *comment);
-int dnbd3_add_trusted_namespace(dnbd3_trusted_server_t *server, char *namespace, char *flags);
-int dnbd3_del_trusted_namespace(dnbd3_trusted_server_t *server, char *namespace);
-dnbd3_namespace_t *dnbd3_get_trust_level(dnbd3_host_t *host, char *namespace);
-
-void dnbd3_handle_sigpipe(int signum);
-void dnbd3_handle_sigterm(int signum);
-
-#endif /* UTILS_H_ */
diff --git a/src/server/server.c b/src/server/server.c
index 03e8564..b2e5ba7 100644
--- a/src/server/server.c
+++ b/src/server/server.c
@@ -33,10 +33,7 @@
#include "sockhelper.h"
#include "server.h"
-#include "saveload.h"
-#include "job.h"
#include "net.h"
-#include "rpc.h"
#include "memlog.h"
#define MAX_SERVER_SOCKETS 50 // Assume there will be no more than 50 sockets the server will listen on
@@ -44,14 +41,23 @@ static int sockets[MAX_SERVER_SOCKETS], socket_count = 0;
#ifdef _DEBUG
int _fake_delay = 0;
#endif
-pthread_spinlock_t _spinlock;
-GSList *_dnbd3_clients = NULL;
+dnbd3_client_t *_clients[SERVER_MAX_CLIENTS];
+int _num_clients = 0;
+pthread_spinlock_t _clients_lock;
+
+dnbd3_image_t *_images[SERVER_MAX_IMAGES];
+int _num_images = 0;
+pthread_spinlock_t _images_lock;
+
+dnbd3_alt_server_t *_alt_servers[SERVER_MAX_ALTS];
+int _num_alts = 0;
+pthread_spinlock_t _alts_lock;
+
char *_config_file_name = DEFAULT_SERVER_CONFIG_FILE;
char *_rpc_password = NULL;
char *_cache_dir = NULL;
-GSList *_dnbd3_images = NULL; // of dnbd3_image_t
-GSList *_trusted_servers = NULL;
+
void dnbd3_print_help(char *argv_0)
{
@@ -78,7 +84,9 @@ void dnbd3_print_version()
void dnbd3_cleanup()
{
- int fd;
+ int fd, i;
+ GSList *iterator = NULL;
+
memlogf("INFO: Cleanup...\n");
for (int i = 0; i < socket_count; ++i)
@@ -90,25 +98,25 @@ void dnbd3_cleanup()
}
socket_count = 0;
- dnbd3_rpc_shutdown();
- dnbd3_job_shutdown();
-
- pthread_spin_lock(&_spinlock);
- GSList *iterator = NULL;
- for (iterator = _dnbd3_clients; iterator; iterator = iterator->next)
+ pthread_spin_lock(&_clients_lock);
+ for (i = 0; i < _num_clients; ++i)
{
- dnbd3_client_t *client = iterator->data;
- shutdown(client->sock, SHUT_RDWR);
- pthread_join(client->thread, NULL);
- g_free(client);
+ dnbd3_client_t * const client = _clients[i];
+ pthread_spin_lock(&client->lock);
+ if (client->sock != -1) shutdown(client->sock, SHUT_RDWR);
+ if (client->thread != 0) pthread_join(client->thread, NULL);
+ _clients[i] = NULL;
+ pthread_spin_unlock(&client->lock);
+ free(client);
}
- g_slist_free(_dnbd3_clients);
-
+ _num_clients = 0;
+ pthread_spin_unlock(&_clients_lock);
- for (iterator = _dnbd3_images; iterator; iterator = iterator->next)
+ pthread_spin_lock(&_images_lock);
+ for (i = 0; i < _num_images; ++i)
{
// save cache maps to files
- dnbd3_image_t *image = iterator->data;
+ dnbd3_image_t *image = _images[i];
if (image->cache_file)
{
char tmp[strlen(image->cache_file)+4];
@@ -139,9 +147,8 @@ void dnbd3_cleanup()
free(image->cache_file);
g_free(image);
}
- g_slist_free(_dnbd3_images);
+ pthread_spin_unlock(&_images_lock);
- pthread_spin_unlock(&_spinlock);
exit(EXIT_SUCCESS);
}
@@ -185,15 +192,15 @@ int main(int argc, char *argv[])
break;
case 'r':
printf("INFO: Reloading configuration file...\n\n");
- dnbd3_rpc_send(RPC_RELOAD);
+ //dnbd3_rpc_send(RPC_RELOAD);
return EXIT_SUCCESS;
case 's':
printf("INFO: Stopping running server...\n\n");
- dnbd3_rpc_send(RPC_EXIT);
+ //dnbd3_rpc_send(RPC_EXIT);
return EXIT_SUCCESS;
case 'i':
printf("INFO: Requesting information...\n\n");
- dnbd3_rpc_send(RPC_IMG_LIST);
+ //dnbd3_rpc_send(RPC_IMG_LIST);
return EXIT_SUCCESS;
case 'H':
dnbd3_print_help(argv[0]);
@@ -298,7 +305,7 @@ int main(int argc, char *argv[])
_dnbd3_clients = g_slist_prepend(_dnbd3_clients, dnbd3_client);
pthread_spin_unlock(&_spinlock);
- if (0 != pthread_create(&(dnbd3_client->thread), NULL, dnbd3_handle_query, (void *) (uintptr_t) dnbd3_client))
+ if (0 != pthread_create(&(dnbd3_client->thread), NULL, net_client_handler, (void *) (uintptr_t) dnbd3_client))
{
memlogf("[ERROR] Could not start thread for new client.");
pthread_spin_lock(&_spinlock);
diff --git a/src/server/server.h b/src/server/server.h
index 47aa0c0..74ca1a1 100644
--- a/src/server/server.h
+++ b/src/server/server.h
@@ -28,22 +28,30 @@
#include "../config.h"
#include "../types.h"
+typedef struct
+{
+ int fd;
+} dnbd3_connection_t;
+/**
+ * Image struct. An image path could be something like
+ * /mnt/images/rz/zfs/Windows7 ZfS.vmdk.1
+ * and the lower_name would then be
+ * rz/zfs/windows7 zfs.vmdk
+ */
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
+ char *path; // absolute path of the image
+ char *lower_name; // relative path, all lowercase, minus revision ID
+ int rid; // revision of image
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
+ dnbd3_connection_t *uplink; // NULL = local image / completely cached, pointer to a server connection otherwise
+ char working; // TRUE if image exists and completeness is == 100% or a working upstream proxy is connected
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)
+ pthread_spinlock_t lock;
} dnbd3_image_t;
typedef struct
@@ -51,7 +59,8 @@ typedef struct
uint16_t len;
uint8_t data[65535];
} dnbd3_binstring_t;
-// Do not always allocate as much memory as required to hold the entire binstring struct, but only as much as is required to hold the actual data
+// Do not always allocate as much memory as required to hold the entire binstring struct,
+// but only as much as is required to hold the actual data
#define NEW_BINSTRING(_name, _len) \
dnbd3_binstring_t *_name = malloc(sizeof(uint16_t) + _len); \
_name->len = _len
@@ -63,30 +72,37 @@ typedef struct
uint8_t is_server; // TRUE if a server in proxy mode, FALSE if real client
pthread_t thread;
dnbd3_image_t *image;
+ pthread_spinlock_t lock;
GSList *sendqueue; // list of dnbd3_binstring_t*
} dnbd3_client_t;
typedef struct
{
- gchar *comment;
- GSList *namespaces; // List of dnbd3_namespace_t
- dnbd3_host_t host;
- uint8_t unreachable;
-} dnbd3_trusted_server_t;
+ time_t last_told;
+ dnbd3_host_t host;
+ char comment[COMMENT_LENGTH];
+} dnbd3_alt_server_t;
typedef struct
{
- char *name;
- uint8_t auto_replicate;
- uint8_t recursive;
-} dnbd3_namespace_t;
+ char comment[COMMENT_LENGTH];
+ dnbd3_host_t host;
+ dnbd3_host_t mask;
+} dnbd3_acess_rules_t;
-extern GSList *_dnbd3_clients; // of dnbd3_client_t
-extern pthread_spinlock_t _spinlock;
-extern char *_config_file_name, *_rpc_password, *_cache_dir;
-extern GSList *_dnbd3_images; // of dnbd3_image_t
-extern GSList *_trusted_servers;
+extern dnbd3_client_t *_clients[SERVER_MAX_CLIENTS];
+extern int _num_clients;
+extern pthread_spinlock_t _clients_lock;
+
+extern dnbd3_image_t *_images[SERVER_MAX_IMAGES];
+extern int _num_images;
+extern pthread_spinlock_t _images_lock;
+extern dnbd3_alt_server_t *_alt_servers[SERVER_MAX_ALTS];
+extern int _num_alts;
+extern pthread_spinlock_t _alts_lock;
+
+extern char *_config_file_name, *_rpc_password, *_cache_dir;
#ifdef _DEBUG
extern int _fake_delay;
diff --git a/src/server/sockhelper.h b/src/server/sockhelper.h
index 2cbcda1..421b8b5 100644
--- a/src/server/sockhelper.h
+++ b/src/server/sockhelper.h
@@ -53,6 +53,18 @@ void sock_set_nonblock(int sock);
void sock_set_block(int sock);
/**
+ * Take IPv4 as string and a port and fill sockaddr_in struct.
+ * This should be refactored to work for IPv4 and IPv6 and use sockaddr_storage.
+ */
+inline void sock_set_addr4(char *ip, uint16_t port, struct sockaddr_in *addr)
+{
+ memset(addr, 0, sizeof(*addr));
+ addr->sin_family = AF_INET; // IPv4
+ addr->sin_addr.s_addr = inet_addr(ip);
+ addr->sin_port = htons(port); // set port number
+}
+
+/**
* Add given socket to array. Take an existing empty slot ( == -1) if available,
* append to end otherwise. Updates socket count variable passed by reference.
* The passed socket fd is only added if it is != -1 for convenience, so you can
diff --git a/src/server/xmlutil.c b/src/server/xmlutil.c
deleted file mode 100644
index d1163a7..0000000
--- a/src/server/xmlutil.c
+++ /dev/null
@@ -1,43 +0,0 @@
-#include "xmlutil.h"
-#include <libxml/parser.h>
-#include <libxml/xpath.h>
-
-
-char *getTextFromPath(xmlDocPtr doc, char *xpath)
-{
- xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
- if (xpathCtx == NULL)
- return NULL;
- xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression(BAD_CAST xpath, xpathCtx);
- if (xpathObj == NULL)
- {
- xmlXPathFreeContext(xpathCtx);
- return NULL;
- }
- char *retval = NULL;
- if (xpathObj->stringval)
- retval = (char*)xmlStrdup(xpathObj->stringval);
- else if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0 && xpathObj->nodesetval->nodeTab && xpathObj->nodesetval->nodeTab[0])
- {
- retval = (char*)xmlNodeGetContent(xpathObj->nodesetval->nodeTab[0]);
- }
- xmlXPathFreeObject(xpathObj);
- xmlXPathFreeContext(xpathCtx);
- return retval;
-}
-
-
-char createXmlDoc(xmlDocPtr *doc, xmlNodePtr* root, char* rootName)
-{
- *doc = xmlNewDoc(BAD_CAST "1.0");
- if (*doc == NULL)
- return 0;
- *root = xmlNewNode(NULL, BAD_CAST rootName);
- if (*root == NULL)
- {
- xmlFreeDoc(*doc);
- return 0;
- }
- xmlDocSetRootElement(*doc, *root);
- return 1;
-}
diff --git a/src/server/xmlutil.h b/src/server/xmlutil.h
deleted file mode 100644
index 4da8616..0000000
--- a/src/server/xmlutil.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef XMLUTIL_H_
-#define XMLUTIL_H_
-
-#include <libxml/xmlstring.h>
-#include <libxml/tree.h>
-#include <inttypes.h>
-
-char *getTextFromPath(xmlDocPtr doc, char *xpath);
-char createXmlDoc(xmlDocPtr *doc, xmlNodePtr* root, char* rootName);
-
-// Two macros to iterate over a node list
-
-#define FOR_EACH_NODE(_doc, _path, _node) do { \
- xmlXPathContextPtr _makro_xpathCtx = xmlXPathNewContext(_doc); \
- if (_makro_xpathCtx) { \
- xmlXPathObjectPtr _makro_xpathObj = xmlXPathEvalExpression(BAD_CAST _path, _makro_xpathCtx); \
- if (_makro_xpathObj) { \
- int _makro_i_; \
- if (_makro_xpathObj->nodesetval) for (_makro_i_ = 0; _makro_i_ < _makro_xpathObj->nodesetval->nodeNr; ++_makro_i_) \
- { _node = _makro_xpathObj->nodesetval->nodeTab[_makro_i_];
-
-#define END_FOR_EACH \
- } } \
- xmlXPathFreeObject(_makro_xpathObj); \
- } \
- xmlXPathFreeContext(_makro_xpathCtx); \
- } while(0)
-
-// Two macros to deal with temporary pointers
-
-#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)
-
-// Macro to get a node property with automatic pointer handling (see two macros above)
-
-#define XML_GETPROP(_node, _name) (char*)(_makro_ptrlist[(_makro_usedcount >= NUM_POINTERS_IN_LIST ? 0 : _makro_usedcount++)] = xmlGetNoNsProp(_node, BAD_CAST _name))
-
-// Inline function to print a numeric value to a char buffer and add as property
-
-static inline void xmlAddDecimalProp(int64_t value, xmlNodePtr node, char* name)
-{
- char strbuffer[100];
- sprintf(strbuffer, "%" PRId64, value);
- xmlNewProp(node, BAD_CAST name, BAD_CAST strbuffer);
-}
-
-#endif