diff options
author | Lars Müller | 2008-03-01 19:30:38 +0100 |
---|---|---|
committer | Lars Müller | 2008-03-01 19:30:38 +0100 |
commit | 868fec1f8eca7c344fc9ac057b7418331299d9ce (patch) | |
tree | c07cdf11db710dc495c3c7a513cc0f8fd68d6626 /server | |
download | dnbd-868fec1f8eca7c344fc9ac057b7418331299d9ce.tar.gz dnbd-868fec1f8eca7c344fc9ac057b7418331299d9ce.tar.xz dnbd-868fec1f8eca7c344fc9ac057b7418331299d9ce.zip |
Import dnbd* from the former openslx-contrib repo as of revision 92.
openslx-contrib is currently read only and will get removed in some
days.
git-svn-id: http://svn.openslx.org/svn/openslx/contrib/dnbd/trunk@1592 95ad53e4-c205-0410-b2fa-d234c58c8868
Diffstat (limited to 'server')
-rw-r--r-- | server/Makefile | 16 | ||||
-rw-r--r-- | server/filer.c | 120 | ||||
-rw-r--r-- | server/filer.h | 19 | ||||
-rw-r--r-- | server/net.c | 147 | ||||
-rw-r--r-- | server/net.h | 51 | ||||
-rw-r--r-- | server/query.c | 349 | ||||
-rw-r--r-- | server/query.h | 42 | ||||
-rw-r--r-- | server/server.c | 216 | ||||
-rw-r--r-- | server/server.h | 21 |
9 files changed, 981 insertions, 0 deletions
diff --git a/server/Makefile b/server/Makefile new file mode 100644 index 0000000..3d10466 --- /dev/null +++ b/server/Makefile @@ -0,0 +1,16 @@ +SERVER_BIN = dnbd-server +SERVER_SRC = filer.c net.c query.c server.c + +BINS = $(SERVER_BIN) + +CFLAGS = -Wall -D_GNU_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -O2 +LDFLAGS = -lpthread + +$(SERVER_BIN): + $(CC) $(CFLAGS) -o $@ $(SERVER_SRC) $(LDFLAGS) + +all: $(BINS) + +.PHONY: +clean: + -$(RM) *.o $(BINS) *~ diff --git a/server/filer.c b/server/filer.c new file mode 100644 index 0000000..b8412b7 --- /dev/null +++ b/server/filer.c @@ -0,0 +1,120 @@ +/* + * filer.c - open, seeks in and reads from a file + * + * Copyright (C) 2006 Thorsten Zitterell <thorsten@zitterell.de> + */ + +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <pthread.h> + +#include "filer.h" + +/* + * function filer_getcapacity() + * returns: size/capacity of file/device + */ +unsigned long long filer_getcapacity(filer_info_t * filer_info) +{ + return filer_info->size; +} + +/* + * function filer_seekblock(): seek to position in file/block device + * returns: 1 on success, otherwise 0 + */ +static inline int filer_seekblock(filer_info_t * filer_info, off_t newpos) +{ + if (lseek(filer_info->fd, newpos, SEEK_SET) == (off_t) -1) { + return 0; + } + filer_info->pos = newpos; + return 1; +} + +/* + * function filer_readblock(): read bytes at specific position + * returns: 1 on success, otherwise 0 + */ +inline int filer_readblock(filer_info_t * filer_info, void *buf, size_t size, + off_t pos) +{ + size_t remain = size; + int result = 0; + int numblocks = 0; + + if (!filer_seekblock(filer_info, pos)) goto leave; + + while (remain > 0) { + if ((numblocks = read(filer_info->fd, buf, remain)) <= 0) { + if (errno == EINTR) + continue; + goto leave; + } + + if (numblocks == 0) { + goto leave; + } + remain -= numblocks; + buf += numblocks; + } + result = 1; + leave: + filer_info->pos += (size - remain); + return result; +} + +/* + * function filer_init(): open file to be served + * returns: data structure with file information + */ +filer_info_t *filer_init(const char *filename) +{ + filer_info_t *filer_info; + struct stat64 stbuf; + + filer_info = (filer_info_t *) malloc(sizeof(filer_info_t)); + if (!filer_info) + return NULL; + + filer_info->filename = strdup(filename); + if ((filer_info->fd = open(filename, O_RDONLY | O_LARGEFILE)) < 0) { + fprintf(stderr, "ERROR: Cannot open filename \"%s\"\n", + filename); + goto out_free; + } + + stbuf.st_size = 0; + + if (fstat64(filer_info->fd, &stbuf) < 0) { + fprintf(stderr, "ERROR: Cannot stat file \"%s\"\n", + filename); + goto out_free; + } + + /* get file/device size */ + if ((filer_info->size = stbuf.st_size) == 0) { + filer_info->size = lseek64(filer_info->fd, (off_t) 0, SEEK_END); + } + + if (filer_info->size == 0) { + fprintf(stderr, "ERROR: File/device has zero size\n"); + goto out_free; + } + + goto out; + + out_free: + if (filer_info) + free(filer_info); + + filer_info = NULL; + out: + return filer_info; +} diff --git a/server/filer.h b/server/filer.h new file mode 100644 index 0000000..6e39bfa --- /dev/null +++ b/server/filer.h @@ -0,0 +1,19 @@ +#ifndef LINUX_DNBD_FILER_H +#define LINUX_DNBD_FILER_H 1 + +/* information of served file/block device */ +struct filer_info { + const char *filename; + int fd; + unsigned long long size; + off_t pos; +}; + +typedef struct filer_info filer_info_t; + +/* functions */ +unsigned long long filer_getcapacity(filer_info_t * filer); +int inline filer_readblock(filer_info_t * filer_info, void *buf, size_t size, off_t pos); +filer_info_t *filer_init(const char *filename); + +#endif diff --git a/server/net.c b/server/net.c new file mode 100644 index 0000000..02db9aa --- /dev/null +++ b/server/net.c @@ -0,0 +1,147 @@ +/* + * net.c - network stuff for the server + * Copyright (C) 2006 Thorsten Zitterell <thorsten@zitterell.de> + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <pthread.h> + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +#define DNBD_USERSPACE 1 +#include "../common/dnbd-cliserv.h" + +#include "net.h" + +struct listener_s { + pthread_t tid; + net_request_t *request; +}; + +typedef struct listener_s listener_t; +listener_t listener; + +/* + * function net_tx(): send a server reply + */ +void net_tx(net_info_t * net_info, net_reply_t * reply) +{ + if (sendto + (net_info->sock, reply->data, reply->len, 0, + (struct sockaddr *) &net_info->groupnet, + sizeof(net_info->groupnet)) < 0) + fprintf(stderr, "net_tx: mcast sendproblem\n"); + +} + +/* + * function net_rx(): receive a client request + * returns: 1 on correct size of reply, otherwise 0 + */ +int net_rx(net_info_t * net_info, net_request_t * request) +{ + ssize_t n; + + request->clientlen = sizeof(request->client); + + n = recvfrom(net_info->sock, &request->data, + sizeof(request->data), 0, + &request->client, &request->clientlen); + + /* sizeof of request must be size of a DNBD request */ + return (n == sizeof(request->data) ? 1 : 0); +} + +/* + * function net_init(): initialize network for multicast + * returns: structure with network related information + */ +net_info_t *net_init(const char *mnet) +{ + struct ip_mreq mreq; + const int ttl = 64; /* TTL of 64 should be enough */ + u_char loop = 0; + + net_info_t *net_info = NULL; + + net_info = (net_info_t *) malloc(sizeof(net_info_t)); + if (!net_info) + return NULL; + + memset(net_info, 0, sizeof(net_info_t)); + + /* network setup */ + net_info->server.sin_family = AF_INET; + net_info->server.sin_port = htons(DNBD_PORT); + net_info->sock = socket(PF_INET, SOCK_DGRAM, 0); + + if (!inet_aton(mnet, &net_info->server.sin_addr)) { + fprintf(stderr, + "ERROR: multicast group %s is not a valid address!\n", + mnet); + goto out_free; + } + + if (bind + (net_info->sock, (struct sockaddr *) &net_info->server, + sizeof(net_info->server)) < 0) { + fprintf(stderr, "ERROR: binding socket!\n"); + goto out_free; + } + + if (!inet_aton(mnet, &net_info->groupnet.sin_addr)) { + fprintf(stderr, + "ERROR: multicast group %s is not a valid address!\n", + mnet); + goto out_free; + } + + /* multicast setup */ + net_info->groupnet.sin_family = AF_INET; + net_info->groupnet.sin_port = htons(DNBD_PORT); + + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + memcpy(&mreq.imr_multiaddr, &net_info->groupnet.sin_addr, + sizeof(struct in_addr)); + + if (setsockopt + (net_info->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, + sizeof(mreq)) < 0) { + fprintf(stderr, + "ERROR: cannot add multicast membership!\n"); + goto out_free; + } + + if (setsockopt(net_info->sock, IPPROTO_IP, IP_MULTICAST_TTL, + &ttl, sizeof(ttl)) < 0) { + fprintf(stderr, "ERROR: Setting TTL to 2\n"); + goto out_free; + } + + /* no looping, please */ + if (setsockopt + (net_info->sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, + sizeof(loop)) < 0) { + fprintf(stderr, + "ERROR: cannot disable multicast looping!\n"); + goto out_free; + } + + goto out; + + out_free: + fprintf(stderr, + "hint: check kernel multicast support, multicast routing\n"); + if (net_info) + free(net_info); + + net_info = NULL; + out: + return net_info; +} diff --git a/server/net.h b/server/net.h new file mode 100644 index 0000000..d0f12c6 --- /dev/null +++ b/server/net.h @@ -0,0 +1,51 @@ +#ifndef LINUX_DNBD_NET_H +#define LINUX_DNBD_NET_H 1 + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +/* network information */ +struct net_info { + int sock; + struct sockaddr_in server; + struct sockaddr_in groupnet; +}; +typedef struct net_info net_info_t; + +/* structure for received network packet */ +struct net_request { + struct sockaddr_in client; + socklen_t clientlen; + dnbd_request_t data; + size_t len; +}; +typedef struct net_request net_request_t; + +/* structure for network packets to be sent */ +struct net_reply { + void *data; + size_t len; +}; +typedef struct net_reply net_reply_t; + + +/* struct net_info_s net_info; */ + +net_info_t * net_init(); + +/* functions */ +void net_tx(net_info_t *net, net_reply_t *reply); +int net_rx(net_info_t * net, net_request_t *request); + +/* network to host byte order */ +#include <endian.h> +#if __BYTE_ORDER == __BIG_ENDIAN +#define ntohll(x) (x) +#else +#define ntohll(x) bswap_64(x) +#endif + + + +#endif diff --git a/server/query.c b/server/query.c new file mode 100644 index 0000000..59d1864 --- /dev/null +++ b/server/query.c @@ -0,0 +1,349 @@ +/* + * query.c - request/reply handling for the server + * Copyright (C) 2006 Thorsten Zitterell <thorsten@zitterell.de> + */ + +#include <stdio.h> +#include <pthread.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <linux/types.h> +#include <unistd.h> +#include <time.h> + +#define DNBD_USERSPACE 1 +#include "../common/dnbd-cliserv.h" + +#include "query.h" + +/* number of threads used to service requests */ +#define NUM_HANDLER_THREADS 1 /* default */ +#define MAX_BLOCK_SIZE 4096 + +struct query_thread { + query_info_t *query_info; + int id; + pthread_t p_thread; +}; + +struct query_thread query_thread[NUM_HANDLER_THREADS]; + +/* recursive global mutex for our program. */ +pthread_mutex_t query_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +/* mutex to avoid concurrent file access */ +pthread_mutex_t handler_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* global condition variable for our program. */ +pthread_cond_t got_query = PTHREAD_COND_INITIALIZER; + +int num_queries = 0; /* number of pending requests, initially none */ +int max_queries = 100; /* this value should be high enough */ + +query_t *queries = NULL; /* head of linked list of requests. */ +int last_query = 0; /* initial position in circular buffer */ +int next_query = 0; + + +void query_handle(struct query_info *query_info, query_t * query); + +/* + * function query_add_loop(): add incoming requests to circular buffer + */ +void *query_add_loop(void *data) +{ + int rc; + query_t *query; + query_info_t *query_info = (query_info_t *) data; + + int tmp_query; + + while (1) { + + rc = pthread_mutex_lock(&query_mutex); + tmp_query = (next_query + 1) % max_queries; + rc = pthread_mutex_unlock(&query_mutex); + + if (tmp_query == last_query) + continue; + + query = &queries[next_query]; + + /* loop until a proper request arrives */ + while (!net_rx(query_info->net_info, &query->request)) {} + + rc = pthread_mutex_lock(&query_mutex); + + next_query = tmp_query; + + /* increase total number of pending requests */ + num_queries++; + + rc = pthread_mutex_unlock(&query_mutex); + + /* signal that there's a new request to handle */ + rc = pthread_cond_signal(&got_query); + } +} + +/* + * function: query_get(): fetch request from circular buffer + * returns: pointer to request + */ +query_t *query_get(pthread_mutex_t * p_mutex) +{ + int rc; + query_t *query; /* pointer to request */ + + rc = pthread_mutex_lock(p_mutex); + + if (last_query == next_query) + return NULL; + + query = &queries[last_query]; + + last_query = (last_query + 1) % max_queries; + num_queries--; + + rc = pthread_mutex_unlock(p_mutex); + /* return the request to the caller */ + return query; +} + +/* + * function query_handle(): handle a single request. + */ +void query_handle(struct query_info *query_info, query_t * query) +{ + int i, rc; + dnbd_request_t *dnbd_request; + dnbd_request_t *dnbd_old_request; + dnbd_reply_t *dnbd_reply = NULL; + struct dnbd_reply_init *dnbd_reply_init; + int tmp_query; + int recent = 0; + time_t timestamp; + + dnbd_request = (dnbd_request_t *) & query->request.data; + + query->reply.len = 0; + + /* convert data from network to host byte order */ + dnbd_request->magic = ntohl(dnbd_request->magic); + dnbd_request->time = ntohs(dnbd_request->time); + dnbd_request->id = ntohs(dnbd_request->id); + dnbd_request->cmd = ntohs(dnbd_request->cmd); + dnbd_request->pos = ntohll(dnbd_request->pos); + dnbd_request->len = ntohs(dnbd_request->len); + + if (dnbd_request->magic != DNBD_MAGIC) + return; + + /* we ususally only respond to a client */ + if (!(dnbd_request->cmd & DNBD_CMD_CLI)) + return; + + /* does the client ask for our id? */ + if (dnbd_request->id && (dnbd_request->id != query_info->id)) + return; + + switch (dnbd_request->cmd & DNBD_CMD_MASK) { + /* handle init request */ + case DNBD_CMD_INIT: + /* handle heartbeat request */ + case DNBD_CMD_HB: + dnbd_reply_init = + (struct dnbd_reply_init *) query->reply.data; + dnbd_reply_init->magic = htonl(DNBD_MAGIC); + + dnbd_reply_init->capacity = + htonll(filer_getcapacity(query_info->filer_info)); + + dnbd_reply_init->cmd = + htons((dnbd_request->cmd + & ~DNBD_CMD_CLI) | DNBD_CMD_SRV); + + dnbd_reply_init->blksize = htons(MAX_BLOCK_SIZE); + dnbd_reply_init->id = htons(query_info->id); + + query->reply.len = sizeof(struct dnbd_reply_init); + + net_tx(query_info->net_info, &query->reply); + break; + /* handle read request */ + case DNBD_CMD_READ: + timestamp = time(NULL); + + /* burst avoidance */ + rc = pthread_mutex_lock(&query_mutex); + for (i = 2; i < max_queries; i++) { + + tmp_query = + (last_query + (max_queries - i)) % max_queries; + + if (tmp_query == last_query) + break; + + /* check only up to one second */ + if (!tmp_query + || queries[tmp_query].time - timestamp > 1) { + break; + } + dnbd_old_request = + (dnbd_request_t *) & queries[tmp_query]. + request.data; + + /* someone requested the same block before? */ + if (dnbd_request->pos == dnbd_old_request->pos) { + /* was it the same client, then retransmit + as the packet was probably lost, otherwise + drop the request */ + if (!((query->request.clientlen == + queries[tmp_query].request.clientlen) + && + (!memcmp + (&query->request.client, + &queries[tmp_query].request.client, + query->request.clientlen)))) { + recent = 1; + break; + } + else + break; + } + } + rc = pthread_mutex_unlock(&query_mutex); + + if (recent) + break; + + /* size of request block too high? */ + if (dnbd_request->len > MAX_BLOCK_SIZE) + break; + + /* create a DNBD reply packet */ + dnbd_reply = (dnbd_reply_t *) query->reply.data; + + dnbd_reply->magic = htonl(DNBD_MAGIC); + dnbd_reply->time = htons(dnbd_request->time); + dnbd_reply->id = htons(query_info->id); + dnbd_reply->pos = htonll(dnbd_request->pos); + + dnbd_reply->cmd = + htons((dnbd_request->cmd + & ~DNBD_CMD_CLI) | DNBD_CMD_SRV); + + /* read from underlying device/file */ + pthread_mutex_lock(&handler_mutex); + filer_readblock(query_info->filer_info, + (void *) dnbd_reply + + sizeof(struct dnbd_reply), + dnbd_request->len, dnbd_request->pos); + + pthread_mutex_unlock(&handler_mutex); + + query->reply.len = + dnbd_request->len + sizeof(dnbd_reply_t); + + query->time = time(NULL); + + /* send reply */ + net_tx(query_info->net_info, &query->reply); + break; + } + + +} + +/* + * function query_handle_loop(): get queries and handle them in a loop + */ +void *query_handle_loop(void *data) +{ + int rc; + query_t *query; /* pointer to a request */ + int thread_id = *((int *) data); /* thread id */ + + printf("Starting thread '%d'\n", thread_id); + fflush(stdout); + + rc = pthread_mutex_lock(&query_mutex); + + /* do forever.... */ + while (1) { + + if (num_queries > 0) { + /* a request is pending */ + query = query_get(&query_mutex); + + /* got a request? */ + if (query) { + + rc = pthread_mutex_unlock(&query_mutex); + /* handle request */ + query_handle(query_thread[thread_id]. + query_info, query); + + rc = pthread_mutex_lock(&query_mutex); + } + } else { + /* wait for a request to arrive */ + rc = pthread_cond_wait(&got_query, &query_mutex); + } + } +} + +/* + * function query_init(): initialize request handling + * returns: pointer to data structure query_info (see header file) + */ +query_info_t *query_init(net_info_t * net_info, filer_info_t * filer_info, + int id, int threads) +{ + int i; + query_info_t *query_info = NULL; + + query_info = (query_info_t *) malloc(sizeof(query_info_t)); + if (!query_info) + return NULL; + + /* fill query_info structure */ + query_info->net_info = net_info; + query_info->filer_info = filer_info; + query_info->id = id; + + if (!(queries = (query_t *) malloc(sizeof(query_t) * max_queries))) { + free(query_info); + return NULL; + } + + last_query = 0; + next_query = 0; + + /* reserve memory for circular buffer */ + for (i = 0; i < max_queries; i++) { + queries[i].reply.data = + malloc(MAX_BLOCK_SIZE + sizeof(dnbd_reply_t)); + } + + /* create the request-handling threads */ + for (i = 0; i < threads; i++) { + + query_thread[i].id = i; + query_thread[i].query_info = query_info; + + pthread_create(&query_thread[i].p_thread, NULL, + query_handle_loop, + (void *) &query_thread[i].id); + } + + /* create thread for receiving network requests */ + pthread_create(&query_info->p_thread, NULL, + query_add_loop, (void *) query_info); + + return query_info; +} diff --git a/server/query.h b/server/query.h new file mode 100644 index 0000000..f4a9376 --- /dev/null +++ b/server/query.h @@ -0,0 +1,42 @@ +#ifndef LINUX_DNBD_REQUEST_H +#define LINUX_DNBD_REQUEST_H 1 + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <time.h> + +#include "net.h" +#include "filer.h" + +struct query_info { + pthread_t p_thread; + net_info_t *net_info; + filer_info_t *filer_info; + int id; +}; + +typedef struct query_info query_info_t; + +/* query information for requests and replies */ +struct query { + time_t time; + net_request_t request; + net_reply_t reply; +}; + +typedef struct query query_t; + +/* functions */ +query_info_t *query_init(net_info_t *, filer_info_t *, int id, int threads); + +/* host to network byte order */ +#include <endian.h> +#if __BYTE_ORDER == __BIG_ENDIAN +#define htonll(x) (x) +#else +#define htonll(x) bswap_64(x) +#endif + + +#endif diff --git a/server/server.c b/server/server.c new file mode 100644 index 0000000..b701e4c --- /dev/null +++ b/server/server.c @@ -0,0 +1,216 @@ +/* + * main.c - central part of the DNBD server application + * Copyright (C) 2006 Thorsten Zitterell <thorsten@zitterell.de> + */ + +#include <stdio.h> +#include <string.h> +#include <getopt.h> +#include <unistd.h> +#include <stdlib.h> + +/* network includes */ +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <signal.h> + +#define DNBD_USERSPACE 1 +#include "../common/dnbd-cliserv.h" + +#include "server.h" +#include "query.h" +#include "net.h" +#include "filer.h" + + +static int verbose = 0; +static int running = 1; + +/* + * function: handle_signal(): set global variable running to 0 if signal arrives + */ +void handle_signal(int signum) +{ + running = 0; +} + +void server_help(void) +{ + fprintf(stderr, "dnbd-server, version %s\n", DNBD_VERSION); + fprintf(stderr, + "Usage: dnbd-server -m <address> -d <device/file> -i <number>\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "description:\n"); + fprintf(stderr, " -m|--mcast <multicast-address>\n"); + fprintf(stderr, " -d|--device <block device or file>\n"); + fprintf(stderr, " -i|--id <unique identification number>\n"); + fprintf(stderr, " -t|--threads <number of threads>\n"); +} + +/* + * function: server_init(): parse command lines + */ +server_info_t *server_init(int argc, char **argv) +{ + /* cmd + * -1: error + * 0: not defined + * 1: serve + */ + int cmd = 0; + server_info_t *server_info = NULL; + + server_info = (server_info_t *) malloc(sizeof(server_info_t)); + if (!server_info) + return NULL; + + memset(server_info, 0, sizeof(server_info_t)); + + server_info->threads = 1; + + /* return value for getopt */ + int c; + + while (1) { + static struct option long_options[] = { + {"verbose", no_argument, 0, 'v'}, + {"mcast", required_argument, 0, 'm'}, + {"device", required_argument, 0, 'd'}, + {"threads", required_argument, 0, 't'}, + {"id", required_argument, 0, 'i'}, + {0, 0, 0, 0} + }; + /* option index for getopt_long */ + int option_index = 0; + + c = getopt_long(argc, argv, "vm:d:i:t:", + long_options, &option_index); + + /* at end of options? */ + if (c == -1) + break; + + /* + cmd = (cmd ? -1 : xx) is used to set cmd when it was + unset (0) before. Otherwise save error value + */ + switch (c) { + case 'v': + verbose++; + break; + case 'm': + server_info->mnet = optarg; /* multicast address */ + break; + case 'd': + cmd = (cmd ? -1 : 2); /* device/file */ + server_info->filename = optarg; + break; + case 'i': + if (sscanf(optarg, "%u",&server_info->id) != 1) { + fprintf(stderr,"ERROR: Id not a 16bit-integer (>0)\n"); + cmd = -1; + } + break; + case 't': + if (sscanf(optarg, "%u",&server_info->threads) != 1) { + fprintf(stderr,"ERROR: Number of threads is wrong (>0)\n"); + cmd = -1; + } + break; + + default: + cmd = -1; + } + + if (cmd < 0) break; + } + + /* no/wrong command given? */ + if (cmd <= 0) { + server_help(); + goto out_free; + } + + if (!server_info->mnet) { + fprintf(stderr, "ERROR: multicast group was not set!\n"); + goto out_free; + } + + if (!(server_info->id > 0)) { + fprintf(stderr, "ERROR: unique id not set or not valid!\n"); + goto out_free; + } + + if (!(server_info->threads > 0)) { + fprintf(stderr, "ERROR: number of threads is not valid!\n"); + goto out_free; + } + + + /* call function for command */ + goto out; + + out_free: + if (server_info) + free(server_info); + server_info = NULL; + out: + return server_info; +} + +/* + * function: main(): server startup + */ +int main(int argc, char **argv) +{ + + server_info_t *server_info; + + signal(SIGINT, handle_signal); + + /* parse and verify command line options */ + if (!(server_info = server_init(argc, argv))) { + fprintf(stderr, "ERROR: Parsing arguments!\n"); + goto out_server; + } + + /* initialize network configuration and start listener thread */ + if (!(server_info->net_info = net_init(server_info->mnet))) { + fprintf(stderr, "ERROR: Initializing net!\n"); + goto out_net; + } + + if (!(server_info->filer_info = filer_init(server_info->filename))) { + fprintf(stderr, "ERROR: Initializing filer!\n"); + goto out_filer; + } + + /* initialize threads to handle requests */ + if (! + (server_info->query_info = + query_init(server_info->net_info, server_info->filer_info, + server_info->id, server_info->threads))) { + fprintf(stderr, "ERROR: Initializing query!\n"); + goto out_query; + } + + while (running) + pause(); + + fprintf(stdout, "cleaning up...\n"); + out_query: + if (server_info->filer_info) + free(server_info->filer_info); + + out_filer: + if (server_info->net_info) + free(server_info->net_info); + + out_net: + if (server_info) { + free(server_info); + } + out_server: + return 0; +} diff --git a/server/server.h b/server/server.h new file mode 100644 index 0000000..3e36bc3 --- /dev/null +++ b/server/server.h @@ -0,0 +1,21 @@ +#ifndef LINUX_DNBD_SERVER_H +#define LINUX_DNBD_SERVER_H 1 + +#include "filer.h" +#include "net.h" +#include "query.h" + +/* server relevant information mainly given by command line */ +struct server_info { + const char *filename; + int id; + int threads; + const char *mnet; + filer_info_t *filer_info; + net_info_t *net_info; + query_info_t *query_info; +}; + +typedef struct server_info server_info_t; + +#endif |