summaryrefslogblamecommitdiffstats
path: root/server/server.c
blob: b701e4c1445ce115435973ab1590d6cd0b1de4fb (plain) (tree)























































































































































































































                                                                                           
/*
 * 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;
}