YAZ 5.38.1
statserv.c
Go to the documentation of this file.
1/* This file is part of the YAZ toolkit.
2 * Copyright (C) Index Data
3 * See the file LICENSE for details.
4 */
5
10
11#if HAVE_CONFIG_H
12#include <config.h>
13#endif
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <stdarg.h>
19
20#ifdef WIN32
21#include <process.h>
22#include <winsock.h>
23#include <direct.h>
24#endif
25
26#include <yaz/sc.h>
27#include <yaz/tpath.h>
28
29#if HAVE_SYS_TYPES_H
30#include <sys/types.h>
31#endif
32#if HAVE_SYS_WAIT_H
33#include <sys/wait.h>
34#endif
35#if HAVE_UNISTD_H
36#include <unistd.h>
37#endif
38#if HAVE_PWD_H
39#include <pwd.h>
40#endif
41
42#if YAZ_HAVE_XML2
43#include <libxml/parser.h>
44#include <libxml/tree.h>
45#include <libxml/xinclude.h>
46#endif
47
48#if YAZ_POSIX_THREADS
49#include <pthread.h>
50#endif
51
52#include <fcntl.h>
53#include <signal.h>
54#include <errno.h>
55
56#include <yaz/comstack.h>
57#include <yaz/tcpip.h>
58#include <yaz/options.h>
59#include <yaz/errno.h>
60#ifdef USE_XTIMOSI
61#include <yaz/xmosi.h>
62#endif
63#include <yaz/log.h>
64#include "eventl.h"
65#include "session.h"
66#include <yaz/statserv.h>
67#include <yaz/daemon.h>
68#include <yaz/yaz-iconv.h>
69#include <yaz/snprintf.h>
70
71static IOCHAN pListener = NULL;
72
73static char gfs_root_dir[FILENAME_MAX+1];
74static struct gfs_server *gfs_server_list = 0;
75static struct gfs_listen *gfs_listen_list = 0;
76static NMEM gfs_nmem = 0;
77
78static char *me = "statserver"; /* log prefix */
79static char *programname="statserver"; /* full program name */
80#ifdef WIN32
81DWORD current_control_tls;
82static int init_control_tls = 0;
83#elif YAZ_POSIX_THREADS
84static pthread_key_t current_control_tls;
85static int init_control_tls = 0;
86#else
88#endif
89
90/*
91 * default behavior.
92 */
93#define STAT_DEFAULT_LOG_LEVEL "server,session,request"
94
95int check_options(int argc, char **argv);
97 1, /* dynamic mode */
98 0, /* threaded mode */
99 0, /* one shot (single session) */
100 "", /* no PDUs */
101 "", /* diagnostic output to stderr */
102 PROTO_Z3950, /* default application protocol */
103 900, /* idle timeout (seconds) */
104 16*1024*1024, /* maximum PDU size (approx.) to allow */
105 "default-config", /* configuration name to pass to backend */
106 "", /* set user id */
107 0, /* bend_start handler */
108 0, /* bend_stop handler */
109 check_options, /* Default routine, for checking the run-time arguments */
111 "",
112 0, /* default value for inet deamon */
113 0, /* handle (for service, etc) */
114 0, /* bend_init handle */
115 0, /* bend_close handle */
116#ifdef WIN32
117 "Z39.50 Server", /* NT Service Name */
118 "Server", /* NT application Name */
119 "", /* NT Service Dependencies */
120 "Z39.50 Server", /* NT Service Display Name */
121#endif /* WIN32 */
122 "", /* PID fname */
123 0, /* background daemon */
124 "", /* SSL certificate filename */
125 "", /* XML config filename */
126 1 /* keepalive */
127};
128
129static int max_sessions = 0;
130
131static int logbits_set = 0;
132static int log_session = 0; /* one-line logs for session */
133static int log_sessiondetail = 0; /* more detailed stuff */
134static int log_server = 0;
135
136static void log_comstack_error(int level, COMSTACK cs, const char *fmt, ...)
137{
138 char message[512];
139 const char *details = 0;
140 int code = cs_get_error(cs, &details);
141 va_list ap;
142
143 va_start(ap, fmt);
144 yaz_vsnprintf(message, sizeof(message), fmt, ap);
145 va_end(ap);
146
147 if (details)
148 yaz_log(level, "%s: cs=%d msg=%s details=%s",
149 message, code, cs_errmsg(code), details);
150 else
151 yaz_log(level, "%s: cs=%d msg=%s",
152 message, code, cs_errmsg(code));
153}
154
156static void get_logbits(int force)
157{ /* needs to be called after parsing cmd-line args that can set loglevels!*/
158 if (force || !logbits_set)
159 {
160 logbits_set = 1;
162 log_sessiondetail = yaz_log_module_level("sessiondetail");
164 }
165}
166
167
168static int add_listener(char *where, int listen_id);
169
170#if YAZ_HAVE_XML2
171static xmlDocPtr xml_config_doc = 0;
172#endif
173
174#if YAZ_HAVE_XML2
175static xmlNodePtr xml_config_get_root(void)
176{
177 xmlNodePtr ptr = 0;
178 if (xml_config_doc)
179 {
180 ptr = xmlDocGetRootElement(xml_config_doc);
181 if (!ptr || ptr->type != XML_ELEMENT_NODE ||
182 strcmp((const char *) ptr->name, "yazgfs"))
183 {
184 yaz_log(YLOG_WARN, "Bad/missing root element for config %s",
186 return 0;
187 }
188 }
189 return ptr;
190}
191#endif
192
193#if YAZ_HAVE_XML2
194static char *nmem_dup_xml_content(NMEM n, xmlNodePtr ptr)
195{
196 unsigned char *cp;
197 xmlNodePtr p;
198 int len = 1; /* start with 1, because of trailing 0 */
199 unsigned char *str;
200 int first = 1; /* whitespace lead flag .. */
201 /* determine length */
202 for (p = ptr; p; p = p->next)
203 {
204 if (p->type == XML_TEXT_NODE)
205 len += xmlStrlen(p->content);
206 }
207 /* now allocate for the string */
208 str = (unsigned char *) nmem_malloc(n, len);
209 *str = '\0'; /* so we can use strcat */
210 for (p = ptr; p; p = p->next)
211 {
212 if (p->type == XML_TEXT_NODE)
213 {
214 cp = p->content;
215 if (first)
216 {
217 while(*cp && yaz_isspace(*cp))
218 cp++;
219 if (*cp)
220 first = 0; /* reset if we got non-whitespace out */
221 }
222 strcat((char *)str, (const char *)cp); /* append */
223 }
224 }
225 /* remove trailing whitespace */
226 cp = strlen((const char *)str) + str;
227 while (cp != str && yaz_isspace(cp[-1]))
228 cp--;
229 *cp = '\0';
230 /* return resulting string */
231 return (char *) str;
232}
233#endif
234
235#if YAZ_HAVE_XML2
236static struct gfs_server * gfs_server_new(const char *id)
237{
238 struct gfs_server *n = (struct gfs_server *)
239 nmem_malloc(gfs_nmem, sizeof(*n));
240 memcpy(&n->cb, &control_block, sizeof(control_block));
241 n->next = 0;
242 n->host = 0;
243 n->listen_ref = 0;
244 n->cql_transform = 0;
245 n->ccl_transform = 0;
246 n->server_node_ptr = 0;
247 n->directory = 0;
248 n->docpath = 0;
249 n->stylesheet = 0;
251 n->id = nmem_strdup_null(gfs_nmem, id);
253 return n;
254}
255#endif
256
257#if YAZ_HAVE_XML2
258static struct gfs_listen * gfs_listen_new(const char *id,
259 const char *address)
260{
261 struct gfs_listen *n = (struct gfs_listen *)
262 nmem_malloc(gfs_nmem, sizeof(*n));
263 if (id)
264 n->id = nmem_strdup(gfs_nmem, id);
265 else
266 n->id = 0;
267 n->next = 0;
269 return n;
270}
271#endif
272
273static void gfs_server_chdir(struct gfs_server *gfs)
274{
275 if (gfs_root_dir[0])
276 {
277 if (chdir(gfs_root_dir))
279 }
280 if (gfs->directory)
281 {
282 if (chdir(gfs->directory))
283 yaz_log(YLOG_WARN|YLOG_ERRNO, "chdir %s",
284 gfs->directory);
285 }
286}
287
288int control_association(association *assoc, const char *host, int force_open)
289{
290 char vhost[128], *cp;
291 if (host)
292 {
293 strncpy(vhost, host, 127);
294 vhost[127] = '\0';
295 cp = strchr(vhost, ':');
296 if (cp)
297 *cp = '\0';
298 host = vhost;
299 }
300 assoc->server = 0;
302 {
303 struct gfs_server *gfs;
304 for (gfs = gfs_server_list; gfs; gfs = gfs->next)
305 {
306 int listen_match = 0;
307 int host_match = 0;
308 if ( !gfs->host || (host && gfs->host && !strcmp(host, gfs->host)))
309 host_match = 1;
310 if (!gfs->listen_ref)
311 listen_match = 1;
312 else
313 {
314 int i;
315 for (i = 0; gfs->listen_ref[i] != -1; i++)
316 if (gfs->listen_ref[i] == assoc->client_chan->chan_id)
317 listen_match = 1;
318 }
319 if (listen_match && host_match)
320 {
321 if (force_open ||
322 (assoc->last_control != &gfs->cb && assoc->backend))
323 {
325 if (assoc->backend && assoc->init)
326 {
327 gfs_server_chdir(gfs);
328 (assoc->last_control->bend_close)(assoc->backend);
329 }
330 assoc->backend = 0;
331 xfree(assoc->init);
332 assoc->init = 0;
333 }
334 assoc->server = gfs;
335 assoc->last_control = &gfs->cb;
336 statserv_setcontrol(&gfs->cb);
337
338 gfs_server_chdir(gfs);
339 break;
340 }
341 }
342 if (!gfs)
343 {
345 assoc->last_control = 0;
346 return 0;
347 }
348 }
349 else
350 {
352 assoc->last_control = &control_block;
353 }
354 yaz_log(YLOG_DEBUG, "server select: config=%s",
355 assoc->last_control->configname);
356
360 return 1;
361}
362
363#if YAZ_HAVE_XML2
364static void xml_config_read(const char *base_path)
365{
366 struct gfs_server **gfsp = &gfs_server_list;
367 struct gfs_listen **gfslp = &gfs_listen_list;
368 xmlNodePtr ptr = xml_config_get_root();
369
370 if (!ptr)
371 return;
372 for (ptr = ptr->children; ptr; ptr = ptr->next)
373 {
374 struct _xmlAttr *attr;
375 if (ptr->type != XML_ELEMENT_NODE)
376 continue;
377 attr = ptr->properties;
378 if (!strcmp((const char *) ptr->name, "listen"))
379 {
380 /*
381 <listen id="listenerid">tcp:@:9999</listen>
382 */
383 const char *id = 0;
384 const char *address =
385 nmem_dup_xml_content(gfs_nmem, ptr->children);
386 for ( ; attr; attr = attr->next)
387 if (!xmlStrcmp(attr->name, BAD_CAST "id")
388 && attr->children && attr->children->type == XML_TEXT_NODE)
389 id = nmem_dup_xml_content(gfs_nmem, attr->children);
390 if (address)
391 {
392 *gfslp = gfs_listen_new(id, address);
393 gfslp = &(*gfslp)->next;
394 *gfslp = 0; /* make listener list consistent for search */
395 }
396 }
397 else if (!strcmp((const char *) ptr->name, "server"))
398 {
399 xmlNodePtr ptr_server = ptr;
400 xmlNodePtr ptr;
401 const char *listenref = 0;
402 const char *id = 0;
403 struct gfs_server *gfs;
404
405 for ( ; attr; attr = attr->next)
406 if (!xmlStrcmp(attr->name, BAD_CAST "listenref")
407 && attr->children && attr->children->type == XML_TEXT_NODE)
408 listenref = nmem_dup_xml_content(gfs_nmem, attr->children);
409 else if (!xmlStrcmp(attr->name, BAD_CAST "id")
410 && attr->children
411 && attr->children->type == XML_TEXT_NODE)
412 id = nmem_dup_xml_content(gfs_nmem, attr->children);
413 else
414 yaz_log(YLOG_WARN, "Unknown attribute '%s' for server",
415 attr->name);
416 gfs = *gfsp = gfs_server_new(id);
417 gfs->server_node_ptr = ptr_server;
418 if (listenref)
419 {
420 char **refs;
421 int num, i;
422 nmem_strsplit(gfs_nmem, ",", listenref, &refs, &num);
423 gfs->listen_ref = (int*) nmem_malloc(gfs_nmem,
424 sizeof(int) * (num + 1));
425 for (i = 0; i < num; i++)
426 {
427 int id_no;
428 struct gfs_listen *gl = gfs_listen_list;
429 gfs->listen_ref[i] = 0;
430 for (id_no = 1; gl; gl = gl->next, id_no++)
431 if (gl->id && !strcmp(gl->id, refs[i]))
432 {
433 gfs->listen_ref[i] = id_no;
434 break;
435 }
436 if (!gl)
437 yaz_log(YLOG_WARN, "Non-existent listenref '%s' "
438 "in server config element", refs[i]);
439 }
440 gfs->listen_ref[i] = -1;
441 }
442 for (ptr = ptr_server->children; ptr; ptr = ptr->next)
443 {
444 if (ptr->type != XML_ELEMENT_NODE)
445 continue;
446 if (!strcmp((const char *) ptr->name, "host"))
447 {
449 ptr->children);
450 }
451 else if (!strcmp((const char *) ptr->name, "config"))
452 {
453 char fpath[1024];
454 strcpy(gfs->cb.configname,
455 nmem_dup_xml_content(gfs_nmem, ptr->children));
456
458 base_path, 0, fpath))
459 strcpy(gfs->cb.configname, fpath);
460 }
461 else if (!strcmp((const char *) ptr->name, "cql2rpn"))
462 {
463 char fpath[1024];
464 char *fname = nmem_dup_xml_content(gfs_nmem, ptr->children);
465 if (yaz_filepath_resolve(fname, base_path, 0, fpath))
466 fname = fpath;
467
469 if (!gfs->cql_transform)
470 {
472 "open CQL transform file '%s'", fname);
473 exit(1);
474 }
475 }
476 else if (!strcmp((const char *) ptr->name, "ccl2rpn"))
477 {
478 char *fname, fpath[1024];
479 FILE *f;
480
481 fname = nmem_dup_xml_content(gfs_nmem, ptr->children);
482 if (yaz_filepath_resolve(fname, base_path, 0, fpath))
483 fname = fpath;
484
485 if ((f = fopen(fname, "r")) == 0) {
486 yaz_log(YLOG_FATAL, "can't open CCL file '%s'", fname);
487 exit(1);
488 }
489 gfs->ccl_transform = ccl_qual_mk();
491 fclose(f);
492 }
493 else if (!strcmp((const char *) ptr->name, "directory"))
494 {
495 gfs->directory =
496 nmem_dup_xml_content(gfs_nmem, ptr->children);
497 }
498 else if (!strcmp((const char *) ptr->name, "docpath"))
499 {
500 gfs->docpath =
501 nmem_dup_xml_content(gfs_nmem, ptr->children);
502 }
503 else if (!strcmp((const char *) ptr->name, "maximumrecordsize"))
504 {
505 gfs->cb.maxrecordsize = atoi(
506 nmem_dup_xml_content(gfs_nmem, ptr->children));
507 }
508 else if (!strcmp((const char *) ptr->name, "stylesheet"))
509 {
510 char *s = nmem_dup_xml_content(gfs_nmem, ptr->children);
511 gfs->stylesheet = nmem_printf(gfs_nmem, "/%s", s);
512 }
513 else if (!strcmp((const char *) ptr->name,
514 "client_query_charset"))
515 {
517 nmem_dup_xml_content(gfs_nmem, ptr->children);
518 }
519 else if (!strcmp((const char *) ptr->name, "explain"))
520 {
521 ; /* being processed separately */
522 }
523 else if (!strcmp((const char *) ptr->name, "retrievalinfo"))
524 {
525 if (base_path)
526 yaz_retrieval_set_path(gfs->retrieval, base_path);
527 if (yaz_retrieval_configure(gfs->retrieval, ptr))
528 {
529 yaz_log(YLOG_FATAL, "%s in config %s",
532 exit(1);
533 }
534 }
535 else
536 {
537 yaz_log(YLOG_FATAL, "Unknown element '%s' in config %s",
538 ptr->name, control_block.xml_config);
539 exit(1);
540 }
541 }
542 gfsp = &(*gfsp)->next;
543 }
544 }
545 *gfsp = 0;
546}
547#endif
548
549static int xml_config_open(void)
550{
551 const char *last_p;
552 const char *fname = control_block.xml_config;
553 if (!getcwd(gfs_root_dir, FILENAME_MAX))
554 {
555 yaz_log(YLOG_WARN|YLOG_ERRNO, "getcwd failed");
556 gfs_root_dir[0] = '\0';
557 }
558#ifdef WIN32
559 init_control_tls = 1;
560 current_control_tls = TlsAlloc();
561#elif YAZ_POSIX_THREADS
562 init_control_tls = 1;
563 pthread_key_create(&current_control_tls, 0);
564#endif
565
567#if YAZ_HAVE_XML2
568 if (fname[0] == '\0')
569 return 0;
570
571 if (!xml_config_doc)
572 {
573 xml_config_doc = xmlParseFile(fname);
574 if (!xml_config_doc)
575 {
576 yaz_log(YLOG_FATAL, "Could not parse %s", fname);
577 return -1;
578 }
579 else
580 {
581 int noSubstitutions = xmlXIncludeProcess(xml_config_doc);
582 if (noSubstitutions == -1)
583 {
584 yaz_log(YLOG_WARN, "XInclude processing failed for config %s",
585 fname);
586 return -1;
587 }
588 }
589 }
590 last_p = strrchr(fname,
591#ifdef WIN32
592 '\\'
593#else
594 '/'
595#endif
596 );
597 if (last_p)
598 {
599 WRBUF base_path = wrbuf_alloc();
600 wrbuf_write(base_path, fname, last_p - fname);
601 xml_config_read(wrbuf_cstr(base_path));
602 wrbuf_destroy(base_path);
603 }
604 else
606#endif
607 return 0;
608}
609
610static void xml_config_close(void)
611{
612#if YAZ_HAVE_XML2
613 if (xml_config_doc)
614 {
615 xmlFreeDoc(xml_config_doc);
616 xml_config_doc = 0;
617 }
618#endif
619 gfs_server_list = 0;
621#ifdef WIN32
622 if (init_control_tls)
623 TlsFree(current_control_tls);
624#elif YAZ_POSIX_THREADS
625 if (init_control_tls)
626 pthread_key_delete(current_control_tls);
627#endif
628}
629
631{
632 struct gfs_listen *gfs = gfs_listen_list;
633 int id_no;
634 int ret = 0;
635
636 for (id_no = 1; gfs; gfs = gfs->next, id_no++)
637 {
638 if (!ret && gfs->address)
639 ret = add_listener(gfs->address, id_no);
640 }
641 return ret;
642}
643
644static void xml_config_bend_start(void)
645{
647 {
648 struct gfs_server *gfs = gfs_server_list;
649 for (; gfs; gfs = gfs->next)
650 {
651 yaz_log(YLOG_DEBUG, "xml_config_bend_start config=%s",
652 gfs->cb.configname);
653 statserv_setcontrol(&gfs->cb);
655 {
656 gfs_server_chdir(gfs);
657 (control_block.bend_start)(&gfs->cb);
658 }
659 }
660 }
661 else
662 {
663 yaz_log(YLOG_DEBUG, "xml_config_bend_start default config");
667 }
668}
669
670static void xml_config_bend_stop(void)
671{
673 {
674 struct gfs_server *gfs = gfs_server_list;
675 for (; gfs; gfs = gfs->next)
676 {
677 yaz_log(YLOG_DEBUG, "xml_config_bend_stop config=%s",
678 gfs->cb.configname);
679 statserv_setcontrol(&gfs->cb);
681 (control_block.bend_stop)(&gfs->cb);
682 }
683 }
684 else
685 {
686 yaz_log(YLOG_DEBUG, "xml_config_bend_stop default config");
690 }
691}
692
693static void remove_listeners(void);
694
695/*
696 * handle incoming connect requests.
697 * The dynamic mode is a bit tricky mostly because we want to avoid
698 * doing all of the listening and accepting in the parent - it's
699 * safer that way.
700 */
701#ifdef WIN32
702
703typedef struct _ThreadList ThreadList;
704
705struct _ThreadList
706{
707 HANDLE hThread;
708 IOCHAN pIOChannel;
709 ThreadList *pNext;
710};
711
712static ThreadList *pFirstThread;
713static CRITICAL_SECTION Thread_CritSect;
714static BOOL bInitialized = FALSE;
715
716static void ThreadList_Initialize()
717{
718 /* Initialize the critical Sections */
719 InitializeCriticalSection(&Thread_CritSect);
720
721 /* Set the first thraed */
722 pFirstThread = NULL;
723
724 /* we have been initialized */
725 bInitialized = TRUE;
726}
727
728static void statserv_add(HANDLE hThread, IOCHAN pIOChannel)
729{
730 /* Only one thread can go through this section at a time */
731 EnterCriticalSection(&Thread_CritSect);
732
733 {
734 /* Lets create our new object */
735 ThreadList *pNewThread = (ThreadList *)malloc(sizeof(ThreadList));
736 pNewThread->hThread = hThread;
737 pNewThread->pIOChannel = pIOChannel;
738 pNewThread->pNext = pFirstThread;
739 pFirstThread = pNewThread;
740
741 /* Lets let somebody else create a new object now */
742 LeaveCriticalSection(&Thread_CritSect);
743 }
744}
745
746void statserv_remove(IOCHAN pIOChannel)
747{
748 /* Only one thread can go through this section at a time */
749 EnterCriticalSection(&Thread_CritSect);
750
751 {
752 ThreadList *pCurrentThread = pFirstThread;
753 ThreadList *pNextThread;
754 ThreadList *pPrevThread =NULL;
755
756 /* Step through all the threads */
757 for (; pCurrentThread != NULL; pCurrentThread = pNextThread)
758 {
759 /* We only need to compare on the IO Channel */
760 if (pCurrentThread->pIOChannel == pIOChannel)
761 {
762 /* We have found the thread we want to delete */
763 /* First of all reset the next pointers */
764 if (pPrevThread == NULL)
765 pFirstThread = pCurrentThread->pNext;
766 else
767 pPrevThread->pNext = pCurrentThread->pNext;
768
769 /* All we need todo now is delete the memory */
770 free(pCurrentThread);
771
772 /* No need to look at any more threads */
773 pNextThread = NULL;
774 }
775 else
776 {
777 /* We need to look at another thread */
778 pNextThread = pCurrentThread->pNext;
779 pPrevThread = pCurrentThread;
780 }
781 }
782
783 /* Lets let somebody else remove an object now */
784 LeaveCriticalSection(&Thread_CritSect);
785 }
786}
787
788/* WIN32 statserv_closedown */
789static void statserv_closedown()
790{
791 /* Shouldn't do anything if we are not initialized */
792 if (bInitialized)
793 {
794 int iHandles = 0;
795 HANDLE *pThreadHandles = NULL;
796
797 /* We need to stop threads adding and removing while we */
798 /* start the closedown process */
799 EnterCriticalSection(&Thread_CritSect);
800
801 {
802 /* We have exclusive access to the thread stuff now */
803 /* Y didn't i use a semaphore - Oh well never mind */
804 ThreadList *pCurrentThread = pFirstThread;
805
806 /* Before we do anything else, we need to shutdown the listener */
807 if (pListener != NULL)
809
810 for (; pCurrentThread != NULL; pCurrentThread = pCurrentThread->pNext)
811 {
812 /* Just destroy the IOCHAN, that should do the trick */
813 iochan_destroy(pCurrentThread->pIOChannel);
814 closesocket(pCurrentThread->pIOChannel->fd);
815
816 /* Keep a running count of our handles */
817 iHandles++;
818 }
819
820 if (iHandles > 0)
821 {
822 HANDLE *pCurrentHandle ;
823
824 /* Allocate the thread handle array */
825 pThreadHandles = (HANDLE *)malloc(sizeof(HANDLE) * iHandles);
826 pCurrentHandle = pThreadHandles;
827
828 for (pCurrentThread = pFirstThread;
829 pCurrentThread != NULL;
830 pCurrentThread = pCurrentThread->pNext, pCurrentHandle++)
831 {
832 /* Just the handle */
833 *pCurrentHandle = pCurrentThread->hThread;
834 }
835 }
836
837 /* We can now leave the critical section */
838 LeaveCriticalSection(&Thread_CritSect);
839 }
840
841 /* Now we can really do something */
842 if (iHandles > 0)
843 {
844 yaz_log(log_server, "waiting for %d to die", iHandles);
845 /* This will now wait, until all the threads close */
846 WaitForMultipleObjects(iHandles, pThreadHandles, TRUE, INFINITE);
847
848 /* Free the memory we allocated for the handle array */
849 free(pThreadHandles);
850 }
851
853 /* No longer require the critical section, since all threads are dead */
854 DeleteCriticalSection(&Thread_CritSect);
855 }
857}
858
859void __cdecl event_loop_thread(IOCHAN iochan)
860{
862}
863
864/* WIN32 listener */
865static void listener(IOCHAN h, int event)
866{
867 COMSTACK line = (COMSTACK) iochan_getdata(h);
868 IOCHAN parent_chan = line->user;
869 association *newas;
870 int res;
871 HANDLE newHandle;
872
873 if (event == EVENT_INPUT)
874 {
875 COMSTACK new_line;
876 IOCHAN new_chan;
877
878 if ((res = cs_listen(line, 0, 0)) < 0)
879 {
881 "cs_listen failed");
882 return;
883 }
884 else if (res == 1)
885 return; /* incomplete */
886 yaz_log(YLOG_DEBUG, "listen ok");
887 new_line = cs_accept(line);
888 if (!new_line)
889 {
890 log_comstack_error(YLOG_FATAL, line, "Accept failed");
891 return;
892 }
893 yaz_log(YLOG_DEBUG, "Accept ok");
894
895 if (!(new_chan = iochan_create(cs_fileno(new_line), ir_session,
896 EVENT_INPUT, parent_chan->chan_id)))
897 {
898 yaz_log(YLOG_FATAL, "Failed to create iochan");
900 return;
901 }
902
903 yaz_log(YLOG_DEBUG, "Creating association");
904 if (!(newas = create_association(new_chan, new_line,
906 {
907 yaz_log(YLOG_FATAL, "Failed to create new assoc.");
909 return;
910 }
911 newas->cs_get_mask = EVENT_INPUT;
912 newas->cs_put_mask = 0;
913 newas->cs_accept_mask = 0;
914
915 yaz_log(YLOG_DEBUG, "Setting timeout %d", control_block.idle_timeout);
916 iochan_setdata(new_chan, newas);
917 iochan_settimeout(new_chan, 60);
918
919 /* Now what we need todo is create a new thread with this iochan as
920 the parameter */
921 newHandle = (HANDLE) _beginthread(event_loop_thread, 0, new_chan);
922 if (newHandle == (HANDLE) -1)
923 {
924
925 yaz_log(YLOG_FATAL|YLOG_ERRNO, "Failed to create new thread.");
927 return;
928 }
929 /* We successfully created the thread, so add it to the list */
930 statserv_add(newHandle, new_chan);
931
932 yaz_log(YLOG_DEBUG, "Created new thread, id = %ld iochan %p",(long) newHandle, new_chan);
933 iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */
934 }
935 else
936 {
937 yaz_log(YLOG_FATAL, "Bad event on listener.");
939 return;
940 }
941}
942
943#else /* ! WIN32 */
944
945/* To save having an #ifdef in event_loop we need to
946 define this empty function
947*/
948void statserv_remove(IOCHAN pIOChannel)
949{
950}
951
952static void statserv_closedown(void)
953{
954 IOCHAN p;
955
957 for (p = pListener; p; p = p->next)
958 {
960 }
962}
963
964static void *new_session(void *vp);
965static int no_sessions = 0;
966
967/* UNIX listener */
968static void listener(IOCHAN h, int event)
969{
970 COMSTACK line = (COMSTACK) iochan_getdata(h);
971 int res;
972
973 if (event == EVENT_INPUT)
974 {
975 COMSTACK new_line;
976 if ((res = cs_listen_check(line, 0, 0, control_block.check_ip,
978 {
980 "cs_listen failed");
981 return;
982 }
983 else if (res == 1)
984 {
985 yaz_log(YLOG_WARN, "cs_listen incomplete");
986 return;
987 }
988 new_line = cs_accept(line);
989 if (!new_line)
990 {
991 log_comstack_error(YLOG_FATAL, line, "Accept failed");
992 iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */
993 return;
994 }
995
998
999 yaz_log(log_sessiondetail, "Connect from %s", cs_addrstr(new_line));
1000
1001 no_sessions++;
1003 {
1004 if ((res = fork()) < 0)
1005 {
1006 yaz_log(YLOG_FATAL|YLOG_ERRNO, "fork");
1007 iochan_destroy(h);
1008 return;
1009 }
1010 else if (res == 0) /* child */
1011 {
1012 char nbuf[100];
1013 IOCHAN pp;
1014
1015 for (pp = pListener; pp; pp = iochan_getnext(pp))
1016 {
1018 cs_close(l);
1019 iochan_destroy(pp);
1020 }
1021 yaz_snprintf(nbuf, sizeof(nbuf), "%s(%d)", me, no_sessions);
1022 yaz_log_init_prefix(nbuf);
1023 /* ensure that bend_stop is not called when each child exits -
1024 only for the main process .. */
1026 }
1027 else /* parent */
1028 {
1029 cs_close(new_line);
1030 return;
1031 }
1032 }
1033
1035 {
1036#if YAZ_POSIX_THREADS
1037 pthread_t child_thread;
1038 pthread_create(&child_thread, 0, new_session, new_line);
1039 pthread_detach(child_thread);
1040#else
1041 new_session(new_line);
1042#endif
1043 }
1044 else
1045 new_session(new_line);
1046 }
1047 else if (event == EVENT_TIMEOUT)
1048 {
1049 yaz_log(log_server, "Shutting down listener.");
1050 iochan_destroy(h);
1051 }
1052 else
1053 {
1054 yaz_log(YLOG_FATAL, "Bad event on listener.");
1055 iochan_destroy(h);
1056 }
1057}
1058
1059static void *new_session(void *vp)
1060{
1061 const char *a;
1062 association *newas;
1063 IOCHAN new_chan;
1064 COMSTACK new_line = (COMSTACK) vp;
1065 IOCHAN parent_chan = (IOCHAN) new_line->user;
1066
1067 unsigned cs_get_mask, cs_accept_mask, mask =
1068 ((new_line->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) |
1069 ((new_line->io_pending & CS_WANT_READ) ? EVENT_INPUT : 0);
1070
1071 if (mask)
1072 {
1073 cs_accept_mask = mask; /* accept didn't complete */
1074 cs_get_mask = 0;
1075 }
1076 else
1077 {
1078 cs_accept_mask = 0; /* accept completed. */
1079 cs_get_mask = mask = EVENT_INPUT;
1080 }
1081
1082 if (!(new_chan = iochan_create(cs_fileno(new_line), ir_session, mask,
1083 parent_chan->chan_id)))
1084 {
1085 yaz_log(YLOG_FATAL, "Failed to create iochan");
1086 return 0;
1087 }
1088 if (!(newas = create_association(new_chan, new_line,
1090 {
1091 yaz_log(YLOG_FATAL, "Failed to create new assoc.");
1092 return 0;
1093 }
1094 newas->cs_accept_mask = cs_accept_mask;
1095 newas->cs_get_mask = cs_get_mask;
1096
1097 iochan_setdata(new_chan, newas);
1098 iochan_settimeout(new_chan, 60);
1099#if 1
1100 a = cs_addrstr(new_line);
1101#else
1102 a = 0;
1103#endif
1105 yaz_log(log_session, "Session - OK %d %s PID=%ld",
1106 no_sessions, a ? a : "[Unknown]", (long) getpid());
1110 {
1111 iochan_event_loop(&new_chan, 0);
1112 }
1113 else
1114 {
1115 new_chan->next = pListener;
1116 pListener = new_chan;
1117 }
1118 return 0;
1119}
1120
1121/* UNIX */
1122#endif
1123
1124static void inetd_connection(int what)
1125{
1126 COMSTACK line;
1127 IOCHAN chan;
1128 association *assoc;
1129 const char *addr;
1130
1131 if ((line = cs_createbysocket(0, tcpip_type, 0, what)))
1132 {
1133 if ((chan = iochan_create(cs_fileno(line), ir_session, EVENT_INPUT,
1134 0)))
1135 {
1136 if ((assoc = create_association(chan, line,
1138 {
1139 iochan_setdata(chan, assoc);
1140 iochan_settimeout(chan, 60);
1141 addr = cs_addrstr(line);
1142 yaz_log(log_sessiondetail, "Inetd association from %s",
1143 addr ? addr : "[UNKNOWN]");
1144 assoc->cs_get_mask = EVENT_INPUT;
1145 }
1146 else
1147 {
1148 yaz_log(YLOG_FATAL, "Failed to create association structure");
1149 }
1150 chan->next = pListener;
1151 pListener = chan;
1152 }
1153 else
1154 {
1155 yaz_log(YLOG_FATAL, "Failed to create iochan");
1156 }
1157 }
1158 else
1159 {
1160 yaz_log(YLOG_ERRNO|YLOG_FATAL, "Failed to create comstack on socket 0");
1161 }
1162}
1163
1164/*
1165 * Set up a listening endpoint, and give it to the event-handler.
1166 */
1167static int add_listener(char *where, int listen_id)
1168{
1169 COMSTACK l;
1170 void *ap;
1171 IOCHAN lst = NULL;
1172 const char *mode;
1173
1175 mode = "dynamic";
1176 else if (control_block.threads)
1177 mode = "threaded";
1178 else
1179 mode = "static";
1180
1181 yaz_log(log_server, "Adding %s listener on %s id=%d PID=%ld", mode, where,
1182 listen_id, (long) getpid());
1183
1184 l = cs_create_host(where, CS_FLAGS_NUMERICHOST, &ap);
1185 if (!l)
1186 {
1187 yaz_log(YLOG_FATAL, "Failed to listen on %s", where);
1188 return -1;
1189 }
1192
1193 if (cs_bind(l, ap, CS_SERVER) < 0)
1194 {
1195 int level = YLOG_FATAL;
1196
1197 if (cs_errno(l) == CSYSERR)
1198 level |= YLOG_ERRNO;
1199 log_comstack_error(level, l, "Failed to bind to %s", where);
1200 cs_close(l);
1201 return -1;
1202 }
1203 if (!(lst = iochan_create(cs_fileno(l), listener, EVENT_INPUT |
1204 EVENT_EXCEPT, listen_id)))
1205 {
1206 yaz_log(YLOG_FATAL|YLOG_ERRNO, "Failed to create IOCHAN-type");
1207 cs_close(l);
1208 return -1;
1209 }
1210 iochan_setdata(lst, l); /* user-defined data for listener is COMSTACK */
1211 l->user = lst; /* user-defined data for COMSTACK is listener chan */
1212
1213 /* Add listener to chain */
1214 lst->next = pListener;
1215 pListener = lst;
1216 return 0; /* OK */
1217}
1218
1219static void remove_listeners(void)
1220{
1221 IOCHAN l = pListener;
1222 for (; l; l = l->next)
1223 iochan_destroy(l);
1224}
1225
1226#ifndef WIN32
1227/* UNIX only (for windows we don't need to catch the signals) */
1228static void catchchld(int num)
1229{
1230 while (waitpid(-1, 0, WNOHANG) > 0)
1231 ;
1232 signal(SIGCHLD, catchchld);
1233}
1234#endif
1235
1237{
1238#ifdef WIN32
1239 if (init_control_tls)
1240 return (statserv_options_block *) TlsGetValue(current_control_tls);
1241 else
1242 return &control_block;
1243#elif YAZ_POSIX_THREADS
1244 if (init_control_tls)
1245 return (statserv_options_block *)
1246 pthread_getspecific(current_control_tls);
1247 else
1248 return &control_block;
1249#else
1251 return current_control_block;
1252 return &control_block;
1253#endif
1254}
1255
1257{
1258 if (gfs_root_dir[0])
1259 {
1260 if (chdir(gfs_root_dir))
1262 }
1263#ifdef WIN32
1264 if (init_control_tls)
1265 TlsSetValue(current_control_tls, block);
1266#elif YAZ_POSIX_THREADS
1267 if (init_control_tls)
1268 pthread_setspecific(current_control_tls, block);
1269#else
1270 current_control_block = block;
1271#endif
1272}
1273
1274static void statserv_reset(void)
1275{
1276}
1277
1278static int sig_received = 0;
1279
1280#ifndef WIN32
1281static void normal_stop_handler(int num)
1282{
1283 sig_received = num;
1284}
1285#endif
1286
1287static void daemon_handler(void *data)
1288{
1289 IOCHAN *pListener = data;
1291}
1292
1293static void show_version(void)
1294{
1295 char vstr[20], sha1_str[41];
1296
1297 yaz_version(vstr, sha1_str);
1298 printf("YAZ version: %s %s\n", YAZ_VERSION, YAZ_VERSION_SHA1);
1299 if (strcmp(sha1_str, YAZ_VERSION_SHA1))
1300 printf("YAZ DLL/SO: %s %s\n", vstr, sha1_str);
1301 exit(0);
1302}
1303
1304static int statserv_sc_main(yaz_sc_t s, int argc, char **argv)
1305{
1306 char sep;
1307#ifdef WIN32
1308 /* We need to initialize the thread list */
1309 ThreadList_Initialize();
1310/* WIN32 */
1311#endif
1312
1313
1314#ifdef WIN32
1315 sep = '\\';
1316#else
1317 sep = '/';
1318#endif
1319 if ((me = strrchr(argv[0], sep)))
1320 me++; /* get the basename */
1321 else
1322 me = argv[0];
1323 programname = argv[0];
1324
1325 if (control_block.options_func(argc, argv))
1326 return 1;
1327
1328 if (xml_config_open())
1329 return 1;
1330
1332
1333 if (control_block.inetd)
1334 {
1335#ifdef WIN32
1336 ; /* no inetd on Windows */
1337#else
1339#endif
1340 }
1341 else
1342 {
1344 return 1;
1345
1346 if (!pListener)
1347 add_listener("tcp:@:9999", 0);
1348
1349#ifndef WIN32
1351 signal(SIGCHLD, catchchld);
1352#endif
1353 }
1354 if (pListener == NULL)
1355 return 1;
1356 if (s)
1357 yaz_sc_running(s);
1358
1359#ifndef WIN32
1360 signal(SIGTERM, normal_stop_handler);
1361#endif
1367#ifndef WIN32
1368 if (sig_received)
1369 yaz_log(YLOG_LOG, "Received SIGTERM PID=%ld", (long) getpid());
1370#endif
1371 return 0;
1372}
1373
1374static void option_copy(char *dst, const char *src)
1375{
1376 strncpy(dst, src ? src : "", BEND_NAME_MAX-1);
1377 dst[BEND_NAME_MAX-1] = '\0';
1378}
1379
1380int check_options(int argc, char **argv)
1381{
1382 int ret = 0, r;
1383 char *arg;
1384
1386
1387 get_logbits(1);
1388
1389 while ((ret = options("1a:iszSTl:v:u:c:w:t:k:Kd:A:p:DC:f:m:r:V",
1390 argv, argc, &arg)) != -2)
1391 {
1392 switch (ret)
1393 {
1394 case 0:
1395 if (add_listener(arg, 0))
1396 return 1; /* failed to create listener */
1397 break;
1398 case '1':
1401 break;
1402 case 'z':
1404 break;
1405 case 's':
1406 fprintf(stderr, "%s: SR protocol no longer supported\n", me);
1407 exit(1);
1408 break;
1409 case 'S':
1411 break;
1412 case 'T':
1413#if YAZ_POSIX_THREADS
1416#else
1417 fprintf(stderr, "%s: Threaded mode not available.\n", me);
1418 return 1;
1419#endif
1420 break;
1421 case 'l':
1424 break;
1425 case 'm':
1426 if (!arg) {
1427 fprintf(stderr, "%s: Specify time format for log file.\n", me);
1428 return(1);
1429 }
1431 break;
1432 case 'v':
1434 get_logbits(1);
1435 break;
1436 case 'a':
1438 break;
1439 case 'u':
1441 break;
1442 case 'c':
1444 break;
1445 case 'C':
1447 break;
1448 case 'd':
1450 break;
1451 case 't':
1452 if (!arg || !(r = atoi(arg)))
1453 {
1454 fprintf(stderr, "%s: Specify positive timeout for -t.\n", me);
1455 return(1);
1456 }
1457 control_block.idle_timeout = strchr(arg, 's') ? r : 60 * r;
1458 break;
1459 case 'k':
1460 if (!arg || !(r = atoi(arg)))
1461 {
1462 fprintf(stderr, "%s: Specify positive size for -k.\n", me);
1463 return(1);
1464 }
1465 control_block.maxrecordsize = r * 1024;
1466 break;
1467 case 'K':
1469 break;
1470 case 'i':
1471 control_block.inetd = 1;
1472 break;
1473 case 'w':
1474 if (chdir(arg))
1475 {
1476 perror(arg);
1477 return 1;
1478 }
1479 break;
1480 case 'A':
1481 max_sessions = atoi(arg);
1482 break;
1483 case 'p':
1485 break;
1486 case 'f':
1487#if YAZ_HAVE_XML2
1489#else
1490 fprintf(stderr, "%s: Option -f unsupported since YAZ is compiled without Libxml2 support\n", me);
1491 exit(1);
1492#endif
1493 break;
1494 case 'D':
1496 break;
1497 case 'r':
1498 if (!arg || !(r = atoi(arg)))
1499 {
1500 fprintf(stderr, "%s: Specify positive size for -r.\n", me);
1501 return(1);
1502 }
1503 yaz_log_init_max_size(r * 1024);
1504 break;
1505 case 'V':
1506 show_version();
1507 break;
1508 default:
1509 fprintf(stderr, "Usage: %s [ -a <pdufile> -v <loglevel>"
1510 " -l <logfile> -u <user> -c <config> -t <minutes>"
1511 " -k <kilobytes> -d <daemon> -p <pidfile> -C certfile"
1512 " -zKiDSTV1 -m <time-format> -w <directory> <listener-addr>... ]\n", me);
1513 return 1;
1514 }
1515 }
1516 return 0;
1517}
1518
1524
1525int statserv_main(int argc, char **argv,
1527 void (*bend_close)(void *handle))
1528{
1529 int ret;
1531
1532 /* control block does not have service_name member on Unix */
1534#ifdef WIN32
1535 cb->service_name, cb->service_display_name
1536#else
1537 0, 0
1538#endif
1539 );
1540
1541 cb->bend_init = bend_init;
1542 cb->bend_close = bend_close;
1543
1544 ret = yaz_sc_program(s, argc, argv, statserv_sc_main, statserv_sc_stop);
1545 yaz_sc_destroy(&s);
1546 return ret;
1547}
1548
1549/*
1550 * Local variables:
1551 * c-basic-offset: 4
1552 * c-file-style: "Stroustrup"
1553 * indent-tabs-mode: nil
1554 * End:
1555 * vim: shiftwidth=4 tabstop=8 expandtab
1556 */
#define BEND_NAME_MAX
Definition backend.h:328
void ccl_qual_file(CCL_bibset bibset, FILE *inf)
Definition cclqfile.c:316
CCL_bibset ccl_qual_mk(void)
creates Bibset
Definition cclqual.c:210
int cs_get_error(COMSTACK cs, const char **details)
Returns the last COMSTACK error and optional transport details.
Definition comstack.c:51
void cs_set_max_recv_bytes(COMSTACK cs, int max_recv_bytes)
Sets the maximum incoming message size.
Definition comstack.c:536
const char * cs_errmsg(int n)
Returns a static message for a COMSTACK error code.
Definition comstack.c:39
COMSTACK cs_create_host(const char *vhost, int flags, void **vp)
Creates an endpoint from a host or URI specification.
Definition comstack.c:177
Transport-independent communication endpoints for BER and HTTP.
#define cs_bind(handle, ad, mo)
Binds an endpoint to a local address.
Definition comstack.h:183
#define cs_addrstr(handle)
Formats the peer address as text.
Definition comstack.h:270
#define cs_close(handle)
Closes the socket and frees the endpoint and its transport state.
Definition comstack.h:223
#define cs_accept(handle)
Creates an endpoint for a connection received by cs_listen.
Definition comstack.h:217
#define cs_errno(handle)
Returns the last COMSTACK error code.
Definition comstack.h:258
#define CS_WANT_READ
Definition comstack.h:302
#define cs_createbysocket(sock, type, flags, proto)
Creates an endpoint around an existing socket.
Definition comstack.h:238
#define cs_fileno(handle)
Returns the socket descriptor, or -1 if none has been created.
Definition comstack.h:247
struct comstack * COMSTACK
Communication endpoint; release with cs_close.
Definition comstack.h:48
#define CS_WANT_WRITE
Definition comstack.h:304
#define CS_SERVER
Definition comstack.h:116
#define cs_listen(handle, ap, al)
Receives an incoming connection for subsequent cs_accept.
Definition comstack.h:194
#define CS_FLAGS_NUMERICHOST
Definition comstack.h:562
#define cs_listen_check(handle, ap, al, cf, cd)
Receives an incoming connection with an optional access check.
Definition comstack.h:207
#define CSYSERR
Definition comstack.h:541
void * malloc(YYSIZE_T)
void free(void *)
cql_transform_t cql_transform_open_fname(const char *fname)
creates a CQL transform handle from a file
int yaz_daemon(const char *progname, unsigned int flags, void(*work)(void *data), void *data, const char *pidfile, const char *uid)
daemon utility.
Definition daemon.c:225
Unix daemon management.
#define YAZ_DAEMON_FORK
Definition daemon.h:41
Header for errno utilities.
int iochan_event_loop(IOCHAN *iochans, int *watch_sig)
Definition eventl.c:81
IOCHAN iochan_create(int fd, IOC_CALLBACK cb, int flags, int chan_id)
Definition eventl.c:42
Definitions for event loop handling for GFS.
#define iochan_settimeout(i, t)
Definition eventl.h:78
#define EVENT_TIMEOUT
Definition eventl.h:52
#define EVENT_INPUT
Definition eventl.h:49
#define iochan_getdata(i)
Definition eventl.h:67
#define iochan_destroy(i)
Definition eventl.h:64
#define EVENT_OUTPUT
Definition eventl.h:50
#define iochan_getnext(i)
Definition eventl.h:77
#define iochan_setdata(i, d)
Definition eventl.h:68
struct iochan * IOCHAN
void statserv_remove(IOCHAN pIOChannel)
Definition statserv.c:948
#define iochan_setflags(i, d)
Definition eventl.h:70
#define EVENT_EXCEPT
Definition eventl.h:51
void yaz_log_init_prefix(const char *prefix)
sets log message prefix
Definition log.c:263
int yaz_log_mask_str(const char *str)
converts log level string to log level (integer)
Definition log.c:606
void yaz_log_init_max_size(int mx)
sets limit in bytes for size for log file
Definition log.c:290
void yaz_log_init_level(int level)
sets log level
Definition log.c:228
void yaz_log_time_format(const char *fmt)
sets time format for log mesages
Definition log.c:529
void yaz_log(int level, const char *fmt,...)
Writes log message.
Definition log.c:487
void yaz_log_init_file(const char *fname)
sets log file
Definition log.c:168
int yaz_log_module_level(const char *name)
returns level for module
Definition log.c:586
Logging utility.
#define YLOG_WARN
log level: warning
Definition log.h:46
#define YLOG_FATAL
log level: fatal
Definition log.h:42
#define YLOG_ERRNO
log level: append system error message
Definition log.h:50
#define YLOG_DEBUG
log level: debugging
Definition log.h:44
#define YLOG_LOG
log level: log (regular)
Definition log.h:48
NMEM nmem_create(void)
returns new NMEM handle
Definition nmem.c:181
void * nmem_malloc(NMEM n, size_t size)
allocates memory block on NMEM handle
Definition nmem.c:145
void nmem_destroy(NMEM n)
destroys NMEM handle and memory associated with it
Definition nmem.c:204
struct nmem_control * NMEM
NMEM handle (an opaque pointer to memory).
Definition nmem.h:44
void nmem_strsplit(NMEM nmem, const char *delim, const char *dstr, char ***darray, int *num)
allocates sub strings out of string using certain delimitors
Definition nmemsdup.c:62
char * nmem_printf(NMEM nmem, const char *fmt,...)
formats and prints a string into NMEM allocated memory
Definition nmemsdup.c:145
char * nmem_strdup(NMEM mem, const char *src)
allocates string on NMEM handle (similar strdup)
Definition nmemsdup.c:19
char * nmem_strdup_null(NMEM mem, const char *src)
allocates string on NMEM handle - allows NULL ptr buffer
Definition nmemsdup.c:26
@ PROTO_Z3950
Definition oid_util.h:47
int options(const char *desc, char **argv, int argc, char **arg)
command-line options parsing for main
Definition options.c:21
Header for command line options parsing utilities.
const char * yaz_retrieval_get_error(yaz_retrieval_t p)
Definition retrieval.c:402
int yaz_retrieval_configure(yaz_retrieval_t p, const xmlNode *ptr)
Definition retrieval.c:292
yaz_retrieval_t yaz_retrieval_create()
Definition retrieval.c:75
void yaz_retrieval_set_path(yaz_retrieval_t p, const char *path)
Definition retrieval.c:407
void yaz_sc_destroy(yaz_sc_t *s)
frees service control handle
Definition sc.c:371
int yaz_sc_program(yaz_sc_t s, int argc, char **argv, int(*sc_main)(yaz_sc_t s, int argc, char **argv), void(*sc_stop)(yaz_sc_t s))
registers service controlled program
Definition sc.c:233
yaz_sc_t yaz_sc_create(const char *service_name, const char *display_name)
creates service handle
Definition sc.c:44
void yaz_sc_running(yaz_sc_t s)
signals that sc_main applicatio starts running
Definition sc.c:226
Header for Windows Service Control utility.
struct sc_s * yaz_sc_t
Definition sc.h:41
static int log_session
Definition seshigh.c:103
static int logbits_set
Definition seshigh.c:102
association * create_association(IOCHAN channel, COMSTACK link, const char *apdufile)
Definition seshigh.c:149
static void get_logbits(void)
Definition seshigh.c:109
void ir_session(IOCHAN h, int event)
Definition seshigh.c:367
static int log_sessiondetail
Definition seshigh.c:104
Internal header for GFS.
int control_association(association *assoc, const char *host, int force)
Definition statserv.c:288
void yaz_vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
Definition snprintf.c:17
void yaz_snprintf(char *buf, size_t size, const char *fmt,...)
Definition snprintf.c:31
Header for config file reading utilities.
static void * new_session(void *vp)
Definition statserv.c:1059
static void option_copy(char *dst, const char *src)
Definition statserv.c:1374
static xmlDocPtr xml_config_doc
Definition statserv.c:171
static int log_server
Definition statserv.c:134
static void log_comstack_error(int level, COMSTACK cs, const char *fmt,...)
Definition statserv.c:136
int statserv_main(int argc, char **argv, bend_initresult *(*bend_init)(bend_initrequest *r), void(*bend_close)(void *handle))
Definition statserv.c:1525
static struct gfs_listen * gfs_listen_list
Definition statserv.c:75
static int max_sessions
Definition statserv.c:129
static int statserv_sc_main(yaz_sc_t s, int argc, char **argv)
Definition statserv.c:1304
static struct gfs_server * gfs_server_new(const char *id)
Definition statserv.c:236
static void gfs_server_chdir(struct gfs_server *gfs)
Definition statserv.c:273
static char gfs_root_dir[FILENAME_MAX+1]
Definition statserv.c:73
static char * nmem_dup_xml_content(NMEM n, xmlNodePtr ptr)
Definition statserv.c:194
static int no_sessions
Definition statserv.c:965
static void statserv_reset(void)
Definition statserv.c:1274
static IOCHAN pListener
Definition statserv.c:71
static char * programname
Definition statserv.c:79
static void catchchld(int num)
Definition statserv.c:1228
static void remove_listeners(void)
Definition statserv.c:1219
static struct gfs_server * gfs_server_list
Definition statserv.c:74
static void inetd_connection(int what)
Definition statserv.c:1124
static NMEM gfs_nmem
Definition statserv.c:76
static void listener(IOCHAN h, int event)
Definition statserv.c:968
static void xml_config_close(void)
Definition statserv.c:610
int check_options(int argc, char **argv)
Definition statserv.c:1380
void statserv_sc_stop(yaz_sc_t s)
Definition statserv.c:1519
static statserv_options_block * current_control_block
Definition statserv.c:87
statserv_options_block control_block
Definition statserv.c:96
#define STAT_DEFAULT_LOG_LEVEL
Definition statserv.c:93
void statserv_setcontrol(statserv_options_block *block)
Definition statserv.c:1256
static int xml_config_add_listeners(void)
Definition statserv.c:630
statserv_options_block * statserv_getcontrol(void)
Definition statserv.c:1236
static void xml_config_read(const char *base_path)
Definition statserv.c:364
static int sig_received
Definition statserv.c:1278
static void xml_config_bend_start(void)
Definition statserv.c:644
static struct gfs_listen * gfs_listen_new(const char *id, const char *address)
Definition statserv.c:258
static void statserv_closedown(void)
Definition statserv.c:952
static void normal_stop_handler(int num)
Definition statserv.c:1281
static int add_listener(char *where, int listen_id)
Definition statserv.c:1167
static void daemon_handler(void *data)
Definition statserv.c:1287
static xmlNodePtr xml_config_get_root(void)
Definition statserv.c:175
static void show_version(void)
Definition statserv.c:1293
static void xml_config_bend_stop(void)
Definition statserv.c:670
static char * me
Definition statserv.c:78
static int xml_config_open(void)
Definition statserv.c:549
Header for GFS (Obsolete. Use yaz/backend.h).
struct bend_initrequest * init
Definition session.h:133
COMSTACK client_link
Definition session.h:109
int cs_put_mask
Definition session.h:130
int cs_get_mask
Definition session.h:129
int maximumRecordSize
Definition session.h:126
int cs_accept_mask
Definition session.h:131
int preferredMessageSize
Definition session.h:125
struct gfs_server * server
Definition session.h:136
void * backend
Definition session.h:119
IOCHAN client_chan
Definition session.h:108
statserv_options_block * last_control
Definition session.h:134
Information for the Init handler.
Definition backend.h:253
result for init handler (must be filled by handler)
Definition backend.h:322
unsigned io_pending
Definition comstack.h:88
void * user
Definition comstack.h:131
char * id
Definition session.h:60
struct gfs_listen * next
Definition session.h:62
char * address
Definition session.h:61
char * directory
Definition session.h:51
CCL_bibset ccl_transform
Definition session.h:49
yaz_retrieval_t retrieval
Definition session.h:55
char * host
Definition session.h:45
char * stylesheet
Definition session.h:53
struct gfs_server * next
Definition session.h:56
char * id
Definition session.h:46
void * server_node_ptr
Definition session.h:50
cql_transform_t cql_transform
Definition session.h:48
int * listen_ref
Definition session.h:47
statserv_options_block cb
Definition session.h:44
char * client_query_charset
Definition session.h:54
char * docpath
Definition session.h:52
struct iochan * next
Definition eventl.h:60
int chan_id
Definition eventl.h:61
control block for server
Definition backend.h:332
char daemon_name[BEND_NAME_MAX]
Definition backend.h:347
char apdufile[BEND_NAME_MAX]
Definition backend.h:336
void(*) bend_stop(struct statserv_options_block *p)
Definition backend.h:344
int(*) options_func(int argc, char **argv)
Definition backend.h:345
char cert_fname[BEND_NAME_MAX]
Definition backend.h:363
bend_initresult *(*) bend_init(bend_initrequest *r)
Definition backend.h:351
char pid_fname[BEND_NAME_MAX]
Definition backend.h:361
enum oid_proto default_proto
Definition backend.h:338
void(*) bend_close(void *handle)
Definition backend.h:352
char xml_config[BEND_NAME_MAX]
Definition backend.h:364
int(*) check_ip(void *cd, const char *addr, int len, int type)
Definition backend.h:346
char setuid[BEND_NAME_MAX]
Definition backend.h:342
char logfile[BEND_NAME_MAX]
Definition backend.h:337
char configname[BEND_NAME_MAX]
Definition backend.h:341
void(*) bend_start(struct statserv_options_block *p)
Definition backend.h:343
int check_ip_tcpd(void *cd, const char *addr, int len, int type)
Definition tcpdchk.c:58
int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname)
Selects certificate and private key files for a TLS endpoint.
Definition tcpip.c:1698
COMSTACK tcpip_type(int s, int flags, int protocol, void *vp)
Definition tcpip.c:238
Header for TCP/IP + SSL COMSTACK.
char * yaz_filepath_resolve(const char *fname, const char *path, const char *base, char *fullpath)
resolve file on path
Definition tpath.c:74
File Path utilities.
unsigned long yaz_version(char *version_str, char *sha1_str)
returns YAZ version
Definition version.c:18
void wrbuf_destroy(WRBUF b)
destroy WRBUF and its buffer
Definition wrbuf.c:38
const char * wrbuf_cstr(WRBUF b)
returns WRBUF content as C-string
Definition wrbuf.c:299
WRBUF wrbuf_alloc(void)
construct WRBUF
Definition wrbuf.c:25
void wrbuf_write(WRBUF b, const char *buf, size_t size)
append constant size buffer to WRBUF
Definition wrbuf.c:68
struct wrbuf * WRBUF
#define xfree(x)
utility macro which calls xfree_f
Definition xmalloc.h:53
void yaz_log_xml_errors(const char *prefix, int log_level)
Makes Libxml2 and Libxslt log errors through yaz_log.
Definition xmlerror.c:47
Header for YAZ iconv interface.
#define yaz_isspace(x)
Definition yaz-iconv.h:87
#define YAZ_VERSION
YAZ version as string.
Definition yaz-version.h:36
#define YAZ_VERSION_SHA1
SHA1 ID for YAZ (Git).
Definition yaz-version.h:45
void bend_close(void *handle)
Definition ztest.c:1167
bend_initresult * bend_init(bend_initrequest *q)
Definition ztest.c:1130