/* This file is part of the YAZ toolkit.
- * Copyright (C) 1995-2010 Index Data
+ * Copyright (C) 1995-2013 Index Data
* See the file LICENSE for details.
*/
* \brief Implements GFS logic
*/
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
#ifdef WIN32
#include <process.h>
#if YAZ_POSIX_THREADS
#include <pthread.h>
-#elif YAZ_GNU_THREADS
-#include <pth.h>
#endif
#include <fcntl.h>
#include "session.h"
#include <yaz/statserv.h>
#include <yaz/daemon.h>
+#include <yaz/yaz-iconv.h>
static IOCHAN pListener = NULL;
"tcp:@:9999", /* default listener port */
PROTO_Z3950, /* default application protocol */
900, /* idle timeout (seconds) */
- 1024*1024, /* maximum PDU size (approx.) to allow */
+ 64*1024*1024, /* maximum PDU size (approx.) to allow */
"default-config", /* configuration name to pass to backend */
"", /* set user id */
0, /* bend_start handler */
"", /* PID fname */
0, /* background daemon */
"", /* SSL certificate filename */
- "" /* XML config filename */
+ "", /* XML config filename */
+ 1 /* keepalive */
};
static int max_sessions = 0;
yaz_log(YLOG_WARN, "Bad/missing root element for config %s",
control_block.xml_config);
return 0;
-
+
}
}
return ptr;
cp = p->content;
if (first)
{
- while(*cp && isspace(*cp))
+ while(*cp && yaz_isspace(*cp))
cp++;
if (*cp)
first = 0; /* reset if we got non-whitespace out */
}
/* remove trailing whitespace */
cp = strlen((const char *)str) + str;
- while (cp != str && isspace(cp[-1]))
+ while (cp != str && yaz_isspace(cp[-1]))
cp--;
*cp = '\0';
/* return resulting string */
#endif
#if YAZ_HAVE_XML2
-static struct gfs_server * gfs_server_new(void)
+static struct gfs_server * gfs_server_new(const char *id)
{
struct gfs_server *n = (struct gfs_server *)
nmem_malloc(gfs_nmem, sizeof(*n));
n->directory = 0;
n->docpath = 0;
n->stylesheet = 0;
+ n->id = nmem_strdup_null(gfs_nmem, id);
n->retrieval = yaz_retrieval_create();
return n;
}
#endif
#if YAZ_HAVE_XML2
-static struct gfs_listen * gfs_listen_new(const char *id,
+static struct gfs_listen * gfs_listen_new(const char *id,
const char *address)
{
struct gfs_listen *n = (struct gfs_listen *)
assoc->server = gfs;
assoc->last_control = &gfs->cb;
statserv_setcontrol(&gfs->cb);
-
+
gfs_server_chdir(gfs);
break;
}
statserv_setcontrol(&control_block);
assoc->last_control = &control_block;
}
- yaz_log(YLOG_DEBUG, "server select: config=%s",
+ yaz_log(YLOG_DEBUG, "server select: config=%s",
assoc->last_control->configname);
assoc->maximumRecordSize = assoc->last_control->maxrecordsize;
struct gfs_server *gfs;
for ( ; attr; attr = attr->next)
- if (!xmlStrcmp(attr->name, BAD_CAST "listenref")
+ if (!xmlStrcmp(attr->name, BAD_CAST "listenref")
&& attr->children && attr->children->type == XML_TEXT_NODE)
listenref = nmem_dup_xml_content(gfs_nmem, attr->children);
else if (!xmlStrcmp(attr->name, BAD_CAST "id")
else
yaz_log(YLOG_WARN, "Unknown attribute '%s' for server",
attr->name);
- gfs = *gfsp = gfs_server_new();
+ gfs = *gfsp = gfs_server_new(id);
gfs->server_node_ptr = ptr_server;
if (listenref)
{
}
else if (!strcmp((const char *) ptr->name, "cql2rpn"))
{
- gfs->cql_transform = cql_transform_open_fname(
- nmem_dup_xml_content(gfs_nmem, ptr->children)
- );
+ char *name = nmem_dup_xml_content(gfs_nmem, ptr->children);
+ gfs->cql_transform = cql_transform_open_fname(name);
+ if (!gfs->cql_transform)
+ {
+ yaz_log(YLOG_FATAL|YLOG_ERRNO,
+ "open CQL transform file '%s'", name);
+ exit(1);
+ }
}
else if (!strcmp((const char *) ptr->name, "ccl2rpn"))
{
}
else if (!strcmp((const char *) ptr->name, "directory"))
{
- gfs->directory =
+ gfs->directory =
nmem_dup_xml_content(gfs_nmem, ptr->children);
}
else if (!strcmp((const char *) ptr->name, "docpath"))
{
- gfs->docpath =
+ gfs->docpath =
nmem_dup_xml_content(gfs_nmem, ptr->children);
}
else if (!strcmp((const char *) ptr->name, "maximumrecordsize"))
else if (!strcmp((const char *) ptr->name, "retrievalinfo"))
{
if (yaz_retrieval_configure(gfs->retrieval, ptr))
- {
+ {
yaz_log(YLOG_FATAL, "%s in config %s",
yaz_retrieval_get_error(gfs->retrieval),
control_block.xml_config);
init_control_tls = 1;
pthread_key_create(¤t_control_tls, 0);
#endif
-
+
gfs_nmem = nmem_create();
#if YAZ_HAVE_XML2
if (control_block.xml_config[0] == '\0')
}
}
+static void remove_listeners(void);
+
/*
* handle incoming connect requests.
* The dynamic mode is a bit tricky mostly because we want to avoid
/* Allocate the thread handle array */
pThreadHandles = (HANDLE *)malloc(sizeof(HANDLE) * iHandles);
- pCurrentHandle = pThreadHandles;
+ pCurrentHandle = pThreadHandles;
for (pCurrentThread = pFirstThread;
pCurrentThread != NULL;
}
/* WIN32 listener */
-static void listener(IOCHAN h, int event)
+static void listener(IOCHAN h, int event)
{
COMSTACK line = (COMSTACK) iochan_getdata(h);
IOCHAN parent_chan = line->user;
newHandle = (HANDLE) _beginthread(event_loop_thread, 0, new_chan);
if (newHandle == (HANDLE) -1)
{
-
+
yaz_log(YLOG_FATAL|YLOG_ERRNO, "Failed to create new thread.");
iochan_destroy(h);
return;
#else /* ! WIN32 */
/* To save having an #ifdef in event_loop we need to
- define this empty function
+ define this empty function
*/
void statserv_remove(IOCHAN pIOChannel)
{
return;
}
+ if (control_block.one_shot)
+ remove_listeners();
+
yaz_log(log_sessiondetail, "Connect from %s", cs_addrstr(new_line));
no_sessions++;
pthread_t child_thread;
pthread_create(&child_thread, 0, new_session, new_line);
pthread_detach(child_thread);
-#elif YAZ_GNU_THREADS
- pth_attr_t attr;
- pth_t child_thread;
-
- attr = pth_attr_new();
- pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
- pth_attr_set(attr, PTH_ATTR_STACK_SIZE, 32*1024);
- pth_attr_set(attr, PTH_ATTR_NAME, "session");
- yaz_log(YLOG_DEBUG, "pth_spawn begin");
- child_thread = pth_spawn(attr, new_session, new_line);
- yaz_log(YLOG_DEBUG, "pth_spawn finish");
- pth_attr_destroy(attr);
#else
new_session(new_line);
#endif
COMSTACK new_line = (COMSTACK) vp;
IOCHAN parent_chan = (IOCHAN) new_line->user;
- unsigned cs_get_mask, cs_accept_mask, mask =
+ unsigned cs_get_mask, cs_accept_mask, mask =
((new_line->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) |
((new_line->io_pending & CS_WANT_READ) ? EVENT_INPUT : 0);
return 0; /* OK */
}
+static void remove_listeners(void)
+{
+ IOCHAN l = pListener;
+ for (; l; l = l->next)
+ iochan_destroy(l);
+}
+
#ifndef WIN32
/* UNIX only (for windows we don't need to catch the signals) */
static void catchchld(int num)
return 1;
xml_config_open();
-
+
xml_config_bend_start();
if (control_block.inetd)
int ret = 0, r;
char *arg;
- yaz_log_init_level(yaz_log_mask_str(STAT_DEFAULT_LOG_LEVEL));
+ yaz_log_init_level(yaz_log_mask_str(STAT_DEFAULT_LOG_LEVEL));
- get_logbits(1);
+ get_logbits(1);
- while ((ret = options("1a:iszSTl:v:u:c:w:t:k:d:A:p:DC:f:m:r:",
+ while ((ret = options("1a:iszSTl:v:u:c:w:t:k:Kd:A:p:DC:f:m:r:",
argv, argc, &arg)) != -2)
{
switch (ret)
if (add_listener(arg, 0))
return 1; /* failed to create listener */
break;
- case '1':
+ case '1':
control_block.one_shot = 1;
control_block.dynamic = 0;
break;
#if YAZ_POSIX_THREADS
control_block.dynamic = 0;
control_block.threads = 1;
-#elif YAZ_GNU_THREADS
- control_block.dynamic = 0;
- control_block.threads = 1;
#else
fprintf(stderr, "%s: Threaded mode not available.\n", me);
return 1;
break;
case 'v':
yaz_log_init_level(yaz_log_mask_str(arg));
- get_logbits(1);
+ get_logbits(1);
break;
case 'a':
option_copy(control_block.apdufile, arg);
}
control_block.maxrecordsize = r * 1024;
break;
+ case 'K':
+ control_block.keepalive = 0;
+ break;
case 'i':
control_block.inetd = 1;
break;
case 'w':
if (chdir(arg))
{
- perror(arg);
+ perror(arg);
return 1;
}
break;
fprintf(stderr, "Usage: %s [ -a <pdufile> -v <loglevel>"
" -l <logfile> -u <user> -c <config> -t <minutes>"
" -k <kilobytes> -d <daemon> -p <pidfile> -C certfile"
- " -ziDST1 -m <time-format> -w <directory> <listener-addr>... ]\n", me);
+ " -zKiDST1 -m <time-format> -w <directory> <listener-addr>... ]\n", me);
return 1;
}
}