git » nmdb » master » tree

[master] / nmdb / main.c

#include <stdio.h>		/* printf() */
#include <unistd.h>		/* malloc(), fork() and getopt() */
#include <stdlib.h>		/* atoi() */
#include <sys/types.h>		/* for pid_t */
#include <string.h>		/* for strcpy() and strlen() */
#include <pthread.h>		/* for pthread_t */

#include "cache.h"
#include "net.h"
#include "dbloop.h"
#include "common.h"
#include "net-const.h"
#include "log.h"
#include "stats.h"
#include "be.h"

#define DEFDBNAME "database"


/* Define the common structures that are used throughout the whole server. */
struct settings settings;
struct stats stats;
struct cache *cache_table;
struct queue *op_queue;


static void help(void) {
	char h[] = \
	  "nmdb [options]\n"
	  "\n"
	  "  -b backend	backend to use (" DEFAULT_BE_NAME ")\n"
	  "  -d dbpath	database path ('database' by default)\n"
	  "  -l lower	TIPC lower port number (10)\n"
	  "  -L upper	TIPC upper port number (= lower)\n"
	  "  -t port	TCP listening port (26010)\n"
	  "  -T addr	TCP listening address (all local addresses)\n"
	  "  -u port	UDP listening port (26010)\n"
	  "  -U addr	UDP listening address (all local addresses)\n"
	  "  -s port	SCTP listening port (26010)\n"
	  "  -S addr	SCTP listening address (all local addresses)\n"
	  "  -c nobj	max. number of objects to be cached, in thousands (128)\n"
	  "  -o fname	log to the given file (stdout).\n"
	  "  -i pidfile file to write the PID to (none).\n"
	  "  -f		don't fork and stay in the foreground\n"
	  "  -p		enable passive mode, for redundancy purposes (read docs.)\n"
	  "  -r		read-only mode\n"
	  "  -h		show this help\n"
	  "\n"
	  "Available backends: " SUPPORTED_BE "\n"
	  "\n"
	  "Please report bugs to Alberto Bertogli (albertito@blitiri.com.ar)\n"
	  "\n";
	printf("%s", h);
}


static int load_settings(int argc, char **argv)
{
	int c;

	settings.tipc_lower = -1;
	settings.tipc_upper = -1;
	settings.tcp_addr = NULL;
	settings.tcp_port = -1;
	settings.udp_addr = NULL;
	settings.udp_port = -1;
	settings.sctp_addr = NULL;
	settings.sctp_port = -1;
	settings.numobjs = -1;
	settings.foreground = 0;
	settings.passive = 0;
	settings.read_only = 0;
	settings.logfname = NULL;
	settings.pidfile = NULL;
	settings.backend = DEFAULT_BE;

	settings.dbname = strdup(DEFDBNAME);
	settings.logfname = strdup("-");

	while ((c = getopt(argc, argv,
				"b:d:l:L:t:T:u:U:s:S:c:o:i:fprh?")) != -1) {
		switch(c) {
		case 'b':
			settings.backend = be_type_from_str(optarg);
			break;
		case 'd':
			free(settings.dbname);
			settings.dbname = strdup(optarg);
			break;

		case 'l':
			settings.tipc_lower = atoi(optarg);
			break;
		case 'L':
			settings.tipc_upper = atoi(optarg);
			break;

		case 't':
			settings.tcp_port = atoi(optarg);
			break;
		case 'T':
			settings.tcp_addr = optarg;
			break;

		case 'u':
			settings.udp_port = atoi(optarg);
			break;
		case 'U':
			settings.udp_addr = optarg;
			break;

		case 's':
			settings.sctp_port = atoi(optarg);
			break;
		case 'S':
			settings.sctp_addr = optarg;
			break;

		case 'c':
			settings.numobjs = atoi(optarg) * 1024;
			break;

		case 'o':
			free(settings.logfname);
			settings.logfname = strdup(optarg);
			break;

		case 'i':
			free(settings.pidfile);
			settings.pidfile = strdup(optarg);
			break;

		case 'f':
			settings.foreground = 1;
			break;
		case 'p':
			settings.passive = 1;
			break;
		case 'r':
			settings.read_only = 1;
			break;

		case 'h':
		case '?':
			help();
			return 0;
		default:
			printf("Unknown parameter '%c'\n", c);
			return 0;
		}
	}

	if (settings.tipc_lower == -1)
		settings.tipc_lower = TIPC_SERVER_INST;
	if (settings.tipc_upper == -1)
		settings.tipc_upper = settings.tipc_lower;
	if (settings.tcp_addr == NULL)
		settings.tcp_addr = TCP_SERVER_ADDR;
	if (settings.tcp_port == -1)
		settings.tcp_port = TCP_SERVER_PORT;
	if (settings.udp_addr == NULL)
		settings.udp_addr = UDP_SERVER_ADDR;
	if (settings.udp_port == -1)
		settings.udp_port = UDP_SERVER_PORT;
	if (settings.sctp_addr == NULL)
		settings.sctp_addr = SCTP_SERVER_ADDR;
	if (settings.sctp_port == -1)
		settings.sctp_port = SCTP_SERVER_PORT;
	if (settings.numobjs == -1)
		settings.numobjs = 128 * 1024;

	if (settings.backend == BE_UNKNOWN) {
		printf("Error: unknown backend\n");
		return 0;
	} else if (settings.backend == BE_UNSUPPORTED) {
		printf("Error: unsupported backend\n");
		return 0;
	}

	return 1;
}


static void free_settings()
{
	free(settings.dbname);
	free(settings.logfname);
	free(settings.pidfile);
}


int main(int argc, char **argv)
{
	struct cache *cd;
	struct queue *q;
	struct db_conn *db;
	pid_t pid;
	pthread_t *dbthread;

	if (!load_settings(argc, argv))
		return 1;

	if (!log_init()) {
		perror("Error opening log file");
		return 1;
	}

	stats_init(&stats);

	cd = cache_create(settings.numobjs, 0);
	if (cd == NULL) {
		errlog("Error creating cache");
		return 1;
	}
	cache_table = cd;

	q = queue_create();
	if (q == NULL) {
		errlog("Error creating queue");
		return 1;
	}
	op_queue = q;

	db = db_open(settings.backend, settings.dbname, 0);
	if (db == NULL) {
		errlog("Error opening DB");
		return 1;
	}
	wlog("Opened database \"%s\" with %s backend\n", settings.dbname,
		be_str_from_type(settings.backend));

	if (!settings.foreground) {
		pid = fork();
		if (pid > 0) {
			/* parent exits */
			return 0;
		} else if (pid < 0) {
			errlog("Error in fork()");
			return 1;
		}

		close(0);
		setsid();
	}

	wlog("Starting nmdb\n");

	write_pid();

	dbthread = db_loop_start(db);

	net_loop();

	db_loop_stop(dbthread);

	db->close(db);

	queue_free(q);

	cache_free(cd);

	if (settings.pidfile)
		unlink(settings.pidfile);

	free_settings();

	return 0;
}