X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=blobdiff_plain;f=src%2Fstatserv.c;h=ab15c2130478c55822dcada8cc42a8e4a20d4196;hp=5556cd14b072359d6081ae334c4c0c7308a8ba5a;hb=43a9d38d20c1b1bcd1a03b2445a501d27526bd35;hpb=b64382a1e420049b882b87fb05fe058aa6592d1c diff --git a/src/statserv.c b/src/statserv.c index 5556cd1..ab15c21 100644 --- a/src/statserv.c +++ b/src/statserv.c @@ -1,11 +1,6 @@ -/* - * Copyright (C) 1995-2006, Index Data ApS +/* This file is part of the YAZ toolkit. + * Copyright (C) 1995-2011 Index Data * See the file LICENSE for details. - * - * NT threaded server code by - * Chas Woodfield, Fretwell Downing Informatics. - * - * $Id: statserv.c,v 1.43 2006-09-27 11:39:02 adam Exp $ */ /** @@ -13,16 +8,23 @@ * \brief Implements GFS logic */ +#if HAVE_CONFIG_H +#include +#endif + #include #include #include #include + #ifdef WIN32 #include #include #include -#include "service.h" #endif + +#include + #if HAVE_SYS_TYPES_H #include #endif @@ -44,8 +46,6 @@ #if YAZ_POSIX_THREADS #include -#elif YAZ_GNU_THREADS -#include #endif #include @@ -55,6 +55,7 @@ #include #include #include +#include #ifdef USE_XTIMOSI #include #endif @@ -62,6 +63,7 @@ #include "eventl.h" #include "session.h" #include +#include static IOCHAN pListener = NULL; @@ -85,20 +87,18 @@ static statserv_options_block *current_control_block = 0; /* * default behavior. */ -#define STAT_DEFAULT_LOG_LEVEL "none,fatal,warn,log,server,session,request" -/* the 'none' clears yaz' own default settings, including [log] */ +#define STAT_DEFAULT_LOG_LEVEL "server,session,request" int check_options(int argc, char **argv); statserv_options_block control_block = { 1, /* dynamic mode */ 0, /* threaded mode */ 0, /* one shot (single session) */ - 0, /* __UNUSED_loglevel */ "", /* no PDUs */ "", /* diagnostic output to stderr */ "tcp:@:9999", /* default listener port */ PROTO_Z3950, /* default application protocol */ - 15, /* idle timeout (minutes) */ + 900, /* idle timeout (seconds) */ 1024*1024, /* maximum PDU size (approx.) to allow */ "default-config", /* configuration name to pass to backend */ "", /* set user id */ @@ -121,7 +121,8 @@ statserv_options_block control_block = { "", /* PID fname */ 0, /* background daemon */ "", /* SSL certificate filename */ - "" /* XML config filename */ + "", /* XML config filename */ + 1 /* keepalive */ }; static int max_sessions = 0; @@ -185,7 +186,7 @@ static char *nmem_dup_xml_content(NMEM n, xmlNodePtr ptr) len += xmlStrlen(p->content); } /* now allocate for the string */ - str = nmem_malloc(n, len); + str = (unsigned char *) nmem_malloc(n, len); *str = '\0'; /* so we can use strcat */ for (p = ptr; p; p = p->next) { @@ -212,28 +213,32 @@ static char *nmem_dup_xml_content(NMEM n, xmlNodePtr ptr) } #endif +#if YAZ_HAVE_XML2 static struct gfs_server * gfs_server_new(void) { - struct gfs_server *n = nmem_malloc(gfs_nmem, sizeof(*n)); + struct gfs_server *n = (struct gfs_server *) + nmem_malloc(gfs_nmem, sizeof(*n)); memcpy(&n->cb, &control_block, sizeof(control_block)); n->next = 0; n->host = 0; n->listen_ref = 0; n->cql_transform = 0; + n->ccl_transform = 0; n->server_node_ptr = 0; n->directory = 0; n->docpath = 0; n->stylesheet = 0; -#if YAZ_HAVE_XML2 n->retrieval = yaz_retrieval_create(); -#endif return n; } +#endif +#if YAZ_HAVE_XML2 static struct gfs_listen * gfs_listen_new(const char *id, const char *address) { - struct gfs_listen *n = nmem_malloc(gfs_nmem, sizeof(*n)); + struct gfs_listen *n = (struct gfs_listen *) + nmem_malloc(gfs_nmem, sizeof(*n)); if (id) n->id = nmem_strdup(gfs_nmem, id); else @@ -242,6 +247,7 @@ static struct gfs_listen * gfs_listen_new(const char *id, n->address = nmem_strdup(gfs_nmem, address); return n; } +#endif static void gfs_server_chdir(struct gfs_server *gfs) { @@ -327,11 +333,11 @@ int control_association(association *assoc, const char *host, int force_open) return 1; } +#if YAZ_HAVE_XML2 static void xml_config_read(void) { struct gfs_server **gfsp = &gfs_server_list; struct gfs_listen **gfslp = &gfs_listen_list; -#if YAZ_HAVE_XML2 xmlNodePtr ptr = xml_config_get_root(); if (!ptr) @@ -403,7 +409,7 @@ static void xml_config_read(void) if (!strcmp((const char *) ptr->name, "host")) { gfs->host = nmem_dup_xml_content(gfs_nmem, - ptr->children); + ptr->children); } else if (!strcmp((const char *) ptr->name, "config")) { @@ -416,6 +422,20 @@ static void xml_config_read(void) nmem_dup_xml_content(gfs_nmem, ptr->children) ); } + else if (!strcmp((const char *) ptr->name, "ccl2rpn")) + { + char *name; + FILE *f; + + name = nmem_dup_xml_content(gfs_nmem, ptr->children); + if ((f = fopen(name, "r")) == 0) { + yaz_log(YLOG_FATAL, "can't open CCL file '%s'", name); + exit(1); + } + gfs->ccl_transform = ccl_qual_mk(); + ccl_qual_file (gfs->ccl_transform, f); + fclose(f); + } else if (!strcmp((const char *) ptr->name, "directory")) { gfs->directory = @@ -434,7 +454,7 @@ static void xml_config_read(void) else if (!strcmp((const char *) ptr->name, "stylesheet")) { char *s = nmem_dup_xml_content(gfs_nmem, ptr->children); - gfs->stylesheet = + gfs->stylesheet = (char *) nmem_malloc(gfs_nmem, strlen(s) + 2); sprintf(gfs->stylesheet, "/%s", s); } @@ -462,9 +482,9 @@ static void xml_config_read(void) gfsp = &(*gfsp)->next; } } -#endif *gfsp = 0; } +#endif static void xml_config_open(void) { @@ -616,7 +636,7 @@ static void ThreadList_Initialize() /* Initialize the critical Sections */ InitializeCriticalSection(&Thread_CritSect); - /* Set the first thraed */ + /* Set the first thraed */ pFirstThread = NULL; /* we have been initialized */ @@ -684,7 +704,7 @@ void statserv_remove(IOCHAN pIOChannel) } /* WIN32 statserv_closedown */ -void statserv_closedown() +static void statserv_closedown() { /* Shouldn't do anything if we are not initialized */ if (bInitialized) @@ -754,9 +774,9 @@ void statserv_closedown() xml_config_close(); } -void __cdecl event_loop_thread (IOCHAN iochan) +void __cdecl event_loop_thread(IOCHAN iochan) { - event_loop (&iochan); + iochan_event_loop(&iochan); } /* WIN32 listener */ @@ -837,27 +857,16 @@ static void listener(IOCHAN h, int event) } } -int statserv_must_terminate(void) -{ - return 0; -} - #else /* ! WIN32 */ -static int term_flag = 0; /* To save having an #ifdef in event_loop we need to define this empty function */ -int statserv_must_terminate(void) -{ - return term_flag; -} - void statserv_remove(IOCHAN pIOChannel) { } -void statserv_closedown() +static void statserv_closedown(void) { IOCHAN p; @@ -869,12 +878,7 @@ void statserv_closedown() xml_config_close(); } -void sigterm(int sig) -{ - term_flag = 1; -} - -static void *new_session (void *vp); +static void *new_session(void *vp); static int no_sessions = 0; /* UNIX listener */ @@ -944,20 +948,8 @@ static void listener(IOCHAN h, int event) { #if YAZ_POSIX_THREADS pthread_t child_thread; - pthread_create (&child_thread, 0, new_session, new_line); - pthread_detach (child_thread); -#elif YAZ_GNU_THREADS - pth_attr_t attr; - pth_t child_thread; - - attr = pth_attr_new (); - pth_attr_set (attr, PTH_ATTR_JOINABLE, FALSE); - pth_attr_set (attr, PTH_ATTR_STACK_SIZE, 32*1024); - pth_attr_set (attr, PTH_ATTR_NAME, "session"); - yaz_log (YLOG_DEBUG, "pth_spawn begin"); - child_thread = pth_spawn (attr, new_session, new_line); - yaz_log (YLOG_DEBUG, "pth_spawn finish"); - pth_attr_destroy (attr); + pthread_create(&child_thread, 0, new_session, new_line); + pthread_detach(child_thread); #else new_session(new_line); #endif @@ -977,13 +969,13 @@ static void listener(IOCHAN h, int event) } } -static void *new_session (void *vp) +static void *new_session(void *vp) { - char *a; + const char *a; association *newas; IOCHAN new_chan; COMSTACK new_line = (COMSTACK) vp; - IOCHAN parent_chan = new_line->user; + IOCHAN parent_chan = (IOCHAN) new_line->user; unsigned cs_get_mask, cs_accept_mask, mask = ((new_line->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) | @@ -1022,13 +1014,14 @@ static void *new_session (void *vp) #else a = 0; #endif + yaz_log_xml_errors(0, YLOG_WARN); yaz_log(log_session, "Session - OK %d %s %ld", no_sessions, a ? a : "[Unknown]", (long) getpid()); if (max_sessions && no_sessions >= max_sessions) control_block.one_shot = 1; if (control_block.threads) { - event_loop(&new_chan); + iochan_event_loop(&new_chan); } else { @@ -1046,7 +1039,7 @@ static void inetd_connection(int what) COMSTACK line; IOCHAN chan; association *assoc; - char *addr; + const char *addr; if ((line = cs_createbysocket(0, tcpip_type, 0, what))) { @@ -1112,15 +1105,19 @@ static int add_listener(char *where, int listen_id) if (cs_bind(l, ap, CS_SERVER) < 0) { - yaz_log(YLOG_FATAL|YLOG_ERRNO, "Failed to bind to %s", where); - cs_close (l); + if (cs_errno(l) == CSYSERR) + yaz_log(YLOG_FATAL|YLOG_ERRNO, "Failed to bind to %s", where); + else + yaz_log(YLOG_FATAL, "Failed to bind to %s: %s", where, + cs_strerror(l)); + cs_close(l); return -1; } if (!(lst = iochan_create(cs_fileno(l), listener, EVENT_INPUT | - EVENT_EXCEPT, listen_id))) + EVENT_EXCEPT, listen_id))) { yaz_log(YLOG_FATAL|YLOG_ERRNO, "Failed to create IOCHAN-type"); - cs_close (l); + cs_close(l); return -1; } iochan_setdata(lst, l); /* user-defined data for listener is COMSTACK */ @@ -1151,7 +1148,8 @@ statserv_options_block *statserv_getcontrol(void) return &control_block; #elif YAZ_POSIX_THREADS if (init_control_tls) - return pthread_getspecific(current_control_tls); + return (statserv_options_block *) + pthread_getspecific(current_control_tls); else return &control_block; #else @@ -1163,7 +1161,11 @@ statserv_options_block *statserv_getcontrol(void) void statserv_setcontrol(statserv_options_block *block) { - chdir(gfs_root_dir); + if (gfs_root_dir[0]) + { + if (chdir(gfs_root_dir)) + yaz_log(YLOG_WARN|YLOG_ERRNO, "chdir %s", gfs_root_dir); + } #ifdef WIN32 if (init_control_tls) TlsSetValue(current_control_tls, block); @@ -1179,7 +1181,13 @@ static void statserv_reset(void) { } -int statserv_start(int argc, char **argv) +static void daemon_handler(void *data) +{ + IOCHAN *pListener = data; + iochan_event_loop(pListener); +} + +static int statserv_sc_main(yaz_sc_t s, int argc, char **argv) { char sep; #ifdef WIN32 @@ -1194,7 +1202,7 @@ int statserv_start(int argc, char **argv) #else sep = '/'; #endif - if ((me = strrchr (argv[0], sep))) + if ((me = strrchr(argv[0], sep))) me++; /* get the basename */ else me = argv[0]; @@ -1207,123 +1215,38 @@ int statserv_start(int argc, char **argv) xml_config_bend_start(); + if (control_block.inetd) + { #ifdef WIN32 - xml_config_add_listeners(); - - yaz_log (log_server, "Starting server %s", me); - if (!pListener && *control_block.default_listen) - add_listener(control_block.default_listen, 0); + ; /* no inetd on Windows */ #else -/* UNIX */ - if (control_block.inetd) inetd_connection(control_block.default_proto); +#endif + } else { - static int hand[2]; - if (control_block.background) - { - /* create pipe so that parent waits until child has created - PID (or failed) */ - if (pipe(hand) < 0) - { - yaz_log(YLOG_FATAL|YLOG_ERRNO, "pipe"); - return 1; - } - switch (fork()) - { - case 0: - break; - case -1: - return 1; - default: - close(hand[1]); - while(1) - { - char dummy[1]; - int res = read(hand[0], dummy, 1); - if (res < 0 && yaz_errno() != EINTR) - { - yaz_log(YLOG_FATAL|YLOG_ERRNO, "read fork handshake"); - break; - } - else if (res >= 0) - break; - } - close(hand[0]); - _exit(0); - } - /* child */ - close(hand[0]); - if (setsid() < 0) - return 1; - - close(0); - close(1); - close(2); - open("/dev/null", O_RDWR); - dup(0); dup(0); - } xml_config_add_listeners(); if (!pListener && *control_block.default_listen) add_listener(control_block.default_listen, 0); - - if (!pListener) - return 1; - if (*control_block.pid_fname) - { - FILE *f = fopen(control_block.pid_fname, "w"); - if (!f) - { - yaz_log(YLOG_FATAL|YLOG_ERRNO, "Couldn't create %s", - control_block.pid_fname); - exit(0); - } - fprintf(f, "%ld", (long) getpid()); - fclose(f); - } - - if (control_block.background) - close(hand[1]); - - - yaz_log (log_server, "Starting server %s pid=%ld", programname, - (long) getpid()); -#if 0 - sigset_t sigs_to_block; - - sigemptyset(&sigs_to_block); - sigaddset (&sigs_to_block, SIGTERM); - pthread_sigmask (SIG_BLOCK, &sigs_to_block, 0); - /* missing... */ -#endif +#ifndef WIN32 if (control_block.dynamic) signal(SIGCHLD, catchchld); - } - signal (SIGPIPE, SIG_IGN); - signal (SIGTERM, sigterm); - if (*control_block.setuid) - { - struct passwd *pw; - - if (!(pw = getpwnam(control_block.setuid))) - { - yaz_log(YLOG_FATAL, "%s: Unknown user", control_block.setuid); - return(1); - } - if (setuid(pw->pw_uid) < 0) - { - yaz_log(YLOG_FATAL|YLOG_ERRNO, "setuid"); - exit(1); - } - } -/* UNIX */ #endif + } if (pListener == NULL) return 1; + if (s) + yaz_sc_running(s); yaz_log(YLOG_DEBUG, "Entering event loop."); - return event_loop(&pListener); + + yaz_daemon(programname, + (control_block.background ? YAZ_DAEMON_FORK : 0), + daemon_handler, &pListener, + *control_block.pid_fname ? control_block.pid_fname : 0, + *control_block.setuid ? control_block.setuid : 0); + return 0; } static void option_copy(char *dst, const char *src) @@ -1337,19 +1260,11 @@ int check_options(int argc, char **argv) int ret = 0, r; char *arg; - if (getenv("YAZ_LOG") == 0) { - /* - * Set default log level. We want to avoid doing this if the - * user has already explicitly specified a preferred default - * log-level, hence the inelegant peek at the YAZ_LOG - * environment variable that will subsequently be interpreted - * by the YAZ logging module itself. - */ - yaz_log_init_level(yaz_log_mask_str(STAT_DEFAULT_LOG_LEVEL)); - } + yaz_log_init_level(yaz_log_mask_str(STAT_DEFAULT_LOG_LEVEL)); get_logbits(1); - while ((ret = options("1a:iszSTl:v:u:c:w:t:k:d:A:p:DC:f:m:", + + while ((ret = options("1a:iszSTl:v:u:c:w:t:k:Kd:A:p:DC:f:m:r:", argv, argc, &arg)) != -2) { switch (ret) @@ -1366,8 +1281,8 @@ int check_options(int argc, char **argv) control_block.default_proto = PROTO_Z3950; break; case 's': - fprintf (stderr, "%s: SR protocol no longer supported\n", me); - exit (1); + fprintf(stderr, "%s: SR protocol no longer supported\n", me); + exit(1); break; case 'S': control_block.dynamic = 0; @@ -1376,9 +1291,6 @@ int check_options(int argc, char **argv) #if YAZ_POSIX_THREADS control_block.dynamic = 0; control_block.threads = 1; -#elif YAZ_GNU_THREADS - control_block.dynamic = 0; - control_block.threads = 1; #else fprintf(stderr, "%s: Threaded mode not available.\n", me); return 1; @@ -1395,12 +1307,10 @@ int check_options(int argc, char **argv) } yaz_log_time_format(arg); break; - case 'v': { - int default_level = yaz_log_mask_str(STAT_DEFAULT_LOG_LEVEL); - yaz_log_init_level(yaz_log_mask_str_x(arg, default_level)); + case 'v': + yaz_log_init_level(yaz_log_mask_str(arg)); get_logbits(1); break; - } case 'a': option_copy(control_block.apdufile, arg); break; @@ -1422,7 +1332,7 @@ int check_options(int argc, char **argv) fprintf(stderr, "%s: Specify positive timeout for -t.\n", me); return(1); } - control_block.idle_timeout = r; + control_block.idle_timeout = strchr(arg, 's') ? r : 60 * r; break; case 'k': if (!arg || !(r = atoi(arg))) @@ -1432,6 +1342,9 @@ int check_options(int argc, char **argv) } control_block.maxrecordsize = r * 1024; break; + case 'K': + control_block.keepalive = 0; + break; case 'i': control_block.inetd = 1; break; @@ -1459,93 +1372,59 @@ int check_options(int argc, char **argv) case 'D': control_block.background = 1; break; + case 'r': + if (!arg || !(r = atoi(arg))) + { + fprintf(stderr, "%s: Specify positive size for -r.\n", me); + return(1); + } + yaz_log_init_max_size(r * 1024); + break; default: fprintf(stderr, "Usage: %s [ -a -v " " -l -u -c -t " " -k -d -p -C certfile" - " -ziDST1 -m -w ... ]\n", me); + " -ziDST1 -m -w ... ]\n", me); return 1; } } return 0; } -#ifdef WIN32 -typedef struct _Args -{ - char **argv; - int argc; -} Args; - -static Args ArgDetails; - -/* name of the executable */ -#define SZAPPNAME "server" - -/* list of service dependencies - "dep1\0dep2\0\0" */ -#define SZDEPENDENCIES "" - -int statserv_main(int argc, char **argv, - bend_initresult *(*bend_init)(bend_initrequest *r), - void (*bend_close)(void *handle)) -{ - struct statserv_options_block *cb = &control_block; - cb->bend_init = bend_init; - cb->bend_close = bend_close; - - /* Lets setup the Arg structure */ - ArgDetails.argc = argc; - ArgDetails.argv = argv; - - /* Now setup the service with the service controller */ - SetupService(argc, argv, &ArgDetails, SZAPPNAME, - cb->service_name, /* internal service name */ - cb->service_display_name, /* displayed name */ - SZDEPENDENCIES); - return 0; -} - -int StartAppService(void *pHandle, int argc, char **argv) +void statserv_sc_stop(yaz_sc_t s) { - /* Initializes the App */ - return 1; -} - -void RunAppService(void *pHandle) -{ - Args *pArgs = (Args *)pHandle; - - /* Starts the app running */ - statserv_start(pArgs->argc, pArgs->argv); -} - -void StopAppService(void *pHandle) -{ - /* Stops the app */ statserv_closedown(); statserv_reset(); } -/* WIN32 */ -#else -/* UNIX */ + int statserv_main(int argc, char **argv, bend_initresult *(*bend_init)(bend_initrequest *r), void (*bend_close)(void *handle)) { int ret; + struct statserv_options_block *cb = &control_block; - control_block.bend_init = bend_init; - control_block.bend_close = bend_close; + /* control block does not have service_name member on Unix */ + yaz_sc_t s = yaz_sc_create( +#ifdef WIN32 + cb->service_name, cb->service_display_name +#else + 0, 0 +#endif + ); - ret = statserv_start (argc, argv); - statserv_closedown (); - statserv_reset(); + cb->bend_init = bend_init; + cb->bend_close = bend_close; + + ret = yaz_sc_program(s, argc, argv, statserv_sc_main, statserv_sc_stop); + yaz_sc_destroy(&s); return ret; } -#endif + /* * Local variables: * c-basic-offset: 4 + * c-file-style: "Stroustrup" * indent-tabs-mode: nil * End: * vim: shiftwidth=4 tabstop=8 expandtab