X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=blobdiff_plain;f=src%2Fstatserv.c;h=815b2e9aabac53832cc7e5bd83f3ae5d1d96720d;hp=487153e5649f8077f9d8a6cc607132bc04a40293;hb=8cb8947e3a7bff4dbf8f124871cb4905df1adce7;hpb=4f3bcae93d51a26709c12b51261c3d95af610cb2 diff --git a/src/statserv.c b/src/statserv.c index 487153e..815b2e9 100644 --- a/src/statserv.c +++ b/src/statserv.c @@ -1,5 +1,5 @@ /* This file is part of the YAZ toolkit. - * Copyright (C) 1995-2011 Index Data + * Copyright (C) Index Data * See the file LICENSE for details. */ @@ -23,6 +23,7 @@ #endif #include +#include #if HAVE_SYS_TYPES_H #include @@ -96,10 +97,9 @@ statserv_options_block control_block = { 0, /* one shot (single session) */ "", /* no PDUs */ "", /* diagnostic output to stderr */ - "tcp:@:9999", /* default listener port */ PROTO_Z3950, /* default application protocol */ 900, /* idle timeout (seconds) */ - 1024*1024, /* maximum PDU size (approx.) to allow */ + 64*1024*1024, /* maximum PDU size (approx.) to allow */ "default-config", /* configuration name to pass to backend */ "", /* set user id */ 0, /* bend_start handler */ @@ -117,7 +117,6 @@ statserv_options_block control_block = { "", /* NT Service Dependencies */ "Z39.50 Server", /* NT Service Display Name */ #endif /* WIN32 */ - 0, /* SOAP handlers */ "", /* PID fname */ 0, /* background daemon */ "", /* SSL certificate filename */ @@ -164,7 +163,6 @@ static xmlNodePtr xml_config_get_root(void) yaz_log(YLOG_WARN, "Bad/missing root element for config %s", control_block.xml_config); return 0; - } } return ptr; @@ -214,7 +212,7 @@ static char *nmem_dup_xml_content(NMEM n, xmlNodePtr ptr) #endif #if YAZ_HAVE_XML2 -static struct gfs_server * gfs_server_new(void) +static struct gfs_server * gfs_server_new(const char *id) { struct gfs_server *n = (struct gfs_server *) nmem_malloc(gfs_nmem, sizeof(*n)); @@ -228,13 +226,15 @@ static struct gfs_server * gfs_server_new(void) n->directory = 0; n->docpath = 0; n->stylesheet = 0; + n->client_query_charset = 0; + n->id = nmem_strdup_null(gfs_nmem, id); n->retrieval = yaz_retrieval_create(); return n; } #endif #if YAZ_HAVE_XML2 -static struct gfs_listen * gfs_listen_new(const char *id, +static struct gfs_listen * gfs_listen_new(const char *id, const char *address) { struct gfs_listen *n = (struct gfs_listen *) @@ -286,9 +286,15 @@ int control_association(association *assoc, const char *host, int force_open) int host_match = 0; if ( !gfs->host || (host && gfs->host && !strcmp(host, gfs->host))) host_match = 1; - if (!gfs->listen_ref || - gfs->listen_ref == assoc->client_chan->chan_id) + if (!gfs->listen_ref) listen_match = 1; + else + { + int i; + for (i = 0; gfs->listen_ref[i] != -1; i++) + if (gfs->listen_ref[i] == assoc->client_chan->chan_id) + listen_match = 1; + } if (listen_match && host_match) { if (force_open || @@ -307,7 +313,7 @@ int control_association(association *assoc, const char *host, int force_open) assoc->server = gfs; assoc->last_control = &gfs->cb; statserv_setcontrol(&gfs->cb); - + gfs_server_chdir(gfs); break; } @@ -324,7 +330,7 @@ int control_association(association *assoc, const char *host, int force_open) statserv_setcontrol(&control_block); assoc->last_control = &control_block; } - yaz_log(YLOG_DEBUG, "server select: config=%s", + yaz_log(YLOG_DEBUG, "server select: config=%s", assoc->last_control->configname); assoc->maximumRecordSize = assoc->last_control->maxrecordsize; @@ -334,7 +340,7 @@ int control_association(association *assoc, const char *host, int force_open) } #if YAZ_HAVE_XML2 -static void xml_config_read(void) +static void xml_config_read(const char *base_path) { struct gfs_server **gfsp = &gfs_server_list; struct gfs_listen **gfslp = &gfs_listen_list; @@ -376,7 +382,7 @@ static void xml_config_read(void) struct gfs_server *gfs; for ( ; attr; attr = attr->next) - if (!xmlStrcmp(attr->name, BAD_CAST "listenref") + if (!xmlStrcmp(attr->name, BAD_CAST "listenref") && attr->children && attr->children->type == XML_TEXT_NODE) listenref = nmem_dup_xml_content(gfs_nmem, attr->children); else if (!xmlStrcmp(attr->name, BAD_CAST "id") @@ -386,21 +392,31 @@ static void xml_config_read(void) else yaz_log(YLOG_WARN, "Unknown attribute '%s' for server", attr->name); - gfs = *gfsp = gfs_server_new(); + gfs = *gfsp = gfs_server_new(id); gfs->server_node_ptr = ptr_server; if (listenref) { - int id_no; - struct gfs_listen *gl = gfs_listen_list; - for (id_no = 1; gl; gl = gl->next, id_no++) - if (gl->id && !strcmp(gl->id, listenref)) - { - gfs->listen_ref = id_no; - break; - } - if (!gl) - yaz_log(YLOG_WARN, "Non-existent listenref '%s' in server " - "config element", listenref); + char **refs; + int num, i; + nmem_strsplit(gfs_nmem, ",", listenref, &refs, &num); + gfs->listen_ref = (int*) nmem_malloc(gfs_nmem, + sizeof(int) * (num + 1)); + for (i = 0; i < num; i++) + { + int id_no; + struct gfs_listen *gl = gfs_listen_list; + gfs->listen_ref[i] = 0; + for (id_no = 1; gl; gl = gl->next, id_no++) + if (gl->id && !strcmp(gl->id, refs[i])) + { + gfs->listen_ref[i] = id_no; + break; + } + if (!gl) + yaz_log(YLOG_WARN, "Non-existent listenref '%s' " + "in server config element", refs[i]); + } + gfs->listen_ref[i] = -1; } for (ptr = ptr_server->children; ptr; ptr = ptr->next) { @@ -413,23 +429,40 @@ static void xml_config_read(void) } else if (!strcmp((const char *) ptr->name, "config")) { + char fpath[1024]; strcpy(gfs->cb.configname, nmem_dup_xml_content(gfs_nmem, ptr->children)); + + if (yaz_filepath_resolve(gfs->cb.configname, + base_path, 0, fpath)) + strcpy(gfs->cb.configname, fpath); } else if (!strcmp((const char *) ptr->name, "cql2rpn")) { - gfs->cql_transform = cql_transform_open_fname( - nmem_dup_xml_content(gfs_nmem, ptr->children) - ); + char fpath[1024]; + char *fname = nmem_dup_xml_content(gfs_nmem, ptr->children); + if (yaz_filepath_resolve(fname, base_path, 0, fpath)) + fname = fpath; + + gfs->cql_transform = cql_transform_open_fname(fname); + if (!gfs->cql_transform) + { + yaz_log(YLOG_FATAL|YLOG_ERRNO, + "open CQL transform file '%s'", fname); + exit(1); + } } else if (!strcmp((const char *) ptr->name, "ccl2rpn")) { - char *name; + char *fname, fpath[1024]; 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); + fname = nmem_dup_xml_content(gfs_nmem, ptr->children); + if (yaz_filepath_resolve(fname, base_path, 0, fpath)) + fname = fpath; + + if ((f = fopen(fname, "r")) == 0) { + yaz_log(YLOG_FATAL, "can't open CCL file '%s'", fname); exit(1); } gfs->ccl_transform = ccl_qual_mk(); @@ -438,12 +471,12 @@ static void xml_config_read(void) } else if (!strcmp((const char *) ptr->name, "directory")) { - gfs->directory = + gfs->directory = nmem_dup_xml_content(gfs_nmem, ptr->children); } else if (!strcmp((const char *) ptr->name, "docpath")) { - gfs->docpath = + gfs->docpath = nmem_dup_xml_content(gfs_nmem, ptr->children); } else if (!strcmp((const char *) ptr->name, "maximumrecordsize")) @@ -458,14 +491,22 @@ static void xml_config_read(void) nmem_malloc(gfs_nmem, strlen(s) + 2); sprintf(gfs->stylesheet, "/%s", s); } + else if (!strcmp((const char *) ptr->name, + "client_query_charset")) + { + gfs->client_query_charset = + nmem_dup_xml_content(gfs_nmem, ptr->children); + } else if (!strcmp((const char *) ptr->name, "explain")) { ; /* being processed separately */ } else if (!strcmp((const char *) ptr->name, "retrievalinfo")) { + if (base_path) + yaz_retrieval_set_path(gfs->retrieval, base_path); if (yaz_retrieval_configure(gfs->retrieval, ptr)) - { + { yaz_log(YLOG_FATAL, "%s in config %s", yaz_retrieval_get_error(gfs->retrieval), control_block.xml_config); @@ -486,8 +527,10 @@ static void xml_config_read(void) } #endif -static void xml_config_open(void) +static int xml_config_open(void) { + const char *last_p; + const char *fname = control_block.xml_config; if (!getcwd(gfs_root_dir, FILENAME_MAX)) { yaz_log(YLOG_WARN|YLOG_ERRNO, "getcwd failed"); @@ -500,19 +543,19 @@ static void xml_config_open(void) init_control_tls = 1; pthread_key_create(¤t_control_tls, 0); #endif - + gfs_nmem = nmem_create(); #if YAZ_HAVE_XML2 - if (control_block.xml_config[0] == '\0') - return; + if (fname[0] == '\0') + return 0; if (!xml_config_doc) { - xml_config_doc = xmlParseFile(control_block.xml_config); + xml_config_doc = xmlParseFile(fname); if (!xml_config_doc) { - yaz_log(YLOG_FATAL, "Could not parse %s", control_block.xml_config); - exit(1); + yaz_log(YLOG_FATAL, "Could not parse %s", fname); + return -1; } else { @@ -520,13 +563,29 @@ static void xml_config_open(void) if (noSubstitutions == -1) { yaz_log(YLOG_WARN, "XInclude processing failed for config %s", - control_block.xml_config); - exit(1); + fname); + return -1; } } } - xml_config_read(); + last_p = strrchr(fname, +#ifdef WIN32 + '\\' +#else + '/' #endif + ); + if (last_p) + { + WRBUF base_path = wrbuf_alloc(); + wrbuf_write(base_path, fname, last_p - fname); + xml_config_read(wrbuf_cstr(base_path)); + wrbuf_destroy(base_path); + } + else + xml_config_read(0); +#endif + return 0; } static void xml_config_close(void) @@ -549,16 +608,18 @@ static void xml_config_close(void) #endif } -static void xml_config_add_listeners(void) +static int xml_config_add_listeners(void) { struct gfs_listen *gfs = gfs_listen_list; int id_no; + int ret = 0; for (id_no = 1; gfs; gfs = gfs->next, id_no++) { - if (gfs->address) - add_listener(gfs->address, id_no); + if (!ret && gfs->address) + ret = add_listener(gfs->address, id_no); } + return ret; } static void xml_config_bend_start(void) @@ -743,7 +804,7 @@ static void statserv_closedown() /* Allocate the thread handle array */ pThreadHandles = (HANDLE *)malloc(sizeof(HANDLE) * iHandles); - pCurrentHandle = pThreadHandles; + pCurrentHandle = pThreadHandles; for (pCurrentThread = pFirstThread; pCurrentThread != NULL; @@ -778,11 +839,11 @@ static void statserv_closedown() void __cdecl event_loop_thread(IOCHAN iochan) { - iochan_event_loop(&iochan); + iochan_event_loop(&iochan, 0); } /* WIN32 listener */ -static void listener(IOCHAN h, int event) +static void listener(IOCHAN h, int event) { COMSTACK line = (COMSTACK) iochan_getdata(h); IOCHAN parent_chan = line->user; @@ -840,7 +901,7 @@ static void listener(IOCHAN h, int event) newHandle = (HANDLE) _beginthread(event_loop_thread, 0, new_chan); if (newHandle == (HANDLE) -1) { - + yaz_log(YLOG_FATAL|YLOG_ERRNO, "Failed to create new thread."); iochan_destroy(h); return; @@ -862,7 +923,7 @@ static void listener(IOCHAN h, int event) #else /* ! WIN32 */ /* To save having an #ifdef in event_loop we need to - define this empty function + define this empty function */ void statserv_remove(IOCHAN pIOChannel) { @@ -982,7 +1043,7 @@ static void *new_session(void *vp) COMSTACK new_line = (COMSTACK) vp; IOCHAN parent_chan = (IOCHAN) new_line->user; - unsigned cs_get_mask, cs_accept_mask, mask = + unsigned cs_get_mask, cs_accept_mask, mask = ((new_line->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) | ((new_line->io_pending & CS_WANT_READ) ? EVENT_INPUT : 0); @@ -1020,13 +1081,13 @@ static void *new_session(void *vp) a = 0; #endif yaz_log_xml_errors(0, YLOG_WARN); - yaz_log(log_session, "Session - OK %d %s %ld", + yaz_log(log_session, "Session - OK %d %s PID=%ld", no_sessions, a ? a : "[Unknown]", (long) getpid()); if (max_sessions && no_sessions >= max_sessions) control_block.one_shot = 1; if (control_block.threads) { - iochan_event_loop(&new_chan); + iochan_event_loop(&new_chan, 0); } else { @@ -1096,8 +1157,8 @@ static int add_listener(char *where, int listen_id) else mode = "static"; - yaz_log(log_server, "Adding %s listener on %s id=%d", mode, where, - listen_id); + yaz_log(log_server, "Adding %s listener on %s id=%d PID=%ld", mode, where, + listen_id, (long) getpid()); l = cs_create_host(where, 2, &ap); if (!l) @@ -1193,10 +1254,30 @@ static void statserv_reset(void) { } +static int sig_received = 0; + +#ifndef WIN32 +static void normal_stop_handler(int num) +{ + sig_received = num; +} +#endif + static void daemon_handler(void *data) { IOCHAN *pListener = data; - iochan_event_loop(pListener); + iochan_event_loop(pListener, &sig_received); +} + +static void show_version(void) +{ + char vstr[20], sha1_str[41]; + + yaz_version(vstr, sha1_str); + printf("YAZ version: %s %s\n", YAZ_VERSION, YAZ_VERSION_SHA1); + if (strcmp(sha1_str, YAZ_VERSION_SHA1)) + printf("YAZ DLL/SO: %s %s\n", vstr, sha1_str); + exit(0); } static int statserv_sc_main(yaz_sc_t s, int argc, char **argv) @@ -1223,8 +1304,9 @@ static int statserv_sc_main(yaz_sc_t s, int argc, char **argv) if (control_block.options_func(argc, argv)) return 1; - xml_config_open(); - + if (xml_config_open()) + return 1; + xml_config_bend_start(); if (control_block.inetd) @@ -1237,10 +1319,11 @@ static int statserv_sc_main(yaz_sc_t s, int argc, char **argv) } else { - xml_config_add_listeners(); + if (xml_config_add_listeners()) + return 1; - if (!pListener && *control_block.default_listen) - add_listener(control_block.default_listen, 0); + if (!pListener) + add_listener("tcp:@:9999", 0); #ifndef WIN32 if (control_block.dynamic) @@ -1251,20 +1334,26 @@ static int statserv_sc_main(yaz_sc_t s, int argc, char **argv) return 1; if (s) yaz_sc_running(s); - yaz_log(YLOG_DEBUG, "Entering event loop."); +#ifndef WIN32 + signal(SIGTERM, normal_stop_handler); +#endif 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); +#ifndef WIN32 + if (sig_received) + yaz_log(YLOG_LOG, "Received SIGTERM PID=%ld", (long) getpid()); +#endif return 0; } static void option_copy(char *dst, const char *src) { - strncpy(dst, src ? src : "", 127); - dst[127] = '\0'; + strncpy(dst, src ? src : "", BEND_NAME_MAX-1); + dst[BEND_NAME_MAX-1] = '\0'; } int check_options(int argc, char **argv) @@ -1272,11 +1361,11 @@ int check_options(int argc, char **argv) int ret = 0, r; char *arg; - 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); + get_logbits(1); - while ((ret = options("1a:iszSTl:v:u:c:w:t:k:Kd:A:p:DC:f:m:r:", + while ((ret = options("1a:iszSTl:v:u:c:w:t:k:Kd:A:p:DC:f:m:r:V", argv, argc, &arg)) != -2) { switch (ret) @@ -1285,7 +1374,7 @@ int check_options(int argc, char **argv) if (add_listener(arg, 0)) return 1; /* failed to create listener */ break; - case '1': + case '1': control_block.one_shot = 1; control_block.dynamic = 0; break; @@ -1321,7 +1410,7 @@ int check_options(int argc, char **argv) break; case 'v': yaz_log_init_level(yaz_log_mask_str(arg)); - get_logbits(1); + get_logbits(1); break; case 'a': option_copy(control_block.apdufile, arg); @@ -1363,7 +1452,7 @@ int check_options(int argc, char **argv) case 'w': if (chdir(arg)) { - perror(arg); + perror(arg); return 1; } break; @@ -1392,11 +1481,14 @@ int check_options(int argc, char **argv) } yaz_log_init_max_size(r * 1024); break; + case 'V': + show_version(); + break; default: fprintf(stderr, "Usage: %s [ -a -v " " -l -u -c -t " " -k -d -p -C certfile" - " -ziDST1 -m -w ... ]\n", me); + " -zKiDSTV1 -m -w ... ]\n", me); return 1; } }