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