X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=blobdiff_plain;f=server%2Fstatserv.c;fp=server%2Fstatserv.c;h=0000000000000000000000000000000000000000;hp=4e3db64cd5301b6b6a800e54d90f17b95f580137;hb=c6e47cbbff56f39f6d81b079ebaeac41d793d4d9;hpb=c71d717ada2a9ef730d527f161eb5ba9aa641a9f diff --git a/server/statserv.c b/server/statserv.c deleted file mode 100644 index 4e3db64..0000000 --- a/server/statserv.c +++ /dev/null @@ -1,961 +0,0 @@ -/* - * Copyright (c) 1995-2003, Index Data - * See the file LICENSE for details. - * Sebastian Hammer, Adam Dickmeiss - * - * NT threaded server code by - * Chas Woodfield, Fretwell Downing Informatics. - * - * $Id: statserv.c,v 1.98 2003-03-03 19:57:35 adam Exp $ - */ - -#include -#include -#ifdef WIN32 -#include -#include -#include -#include "service.h" -#else -#include -#include -#endif - -#if YAZ_POSIX_THREADS -#include -#elif YAZ_GNU_THREADS -#include -#endif - -#include -#include -#include - -#include -#include -#include -#ifdef USE_XTIMOSI -#include -#endif -#include -#include "eventl.h" -#include "session.h" -#include - -static IOCHAN pListener = NULL; - -static char *me = "statserver"; -/* - * default behavior. - */ -int check_options(int argc, char **argv); -statserv_options_block control_block = { - 1, /* dynamic mode */ - 0, /* threaded mode */ - 0, /* one shot (single session) */ - LOG_DEFAULT_LEVEL, /* log level */ - "", /* no PDUs */ - "", /* diagnostic output to stderr */ - "tcp:@:9999", /* default listener port */ - PROTO_Z3950, /* default application protocol */ - 15, /* idle timeout (minutes) */ - 1024*1024, /* maximum PDU size (approx.) to allow */ - "default-config", /* configuration name to pass to backend */ - "", /* set user id */ - 0, /* bend_start handler */ - 0, /* bend_stop handler */ - check_options, /* Default routine, for checking the run-time arguments */ - check_ip_tcpd, - "", - 0, /* default value for inet deamon */ - 0, /* handle (for service, etc) */ - 0, /* bend_init handle */ - 0, /* bend_close handle */ -#ifdef WIN32 - "Z39.50 Server", /* NT Service Name */ - "Server", /* NT application Name */ - "", /* NT Service Dependencies */ - "Z39.50 Server", /* NT Service Display Name */ -#endif /* WIN32 */ - 0 /* SOAP handlers */ -}; - -static int max_sessions = 0; - -/* - * handle incoming connect requests. - * The dynamic mode is a bit tricky mostly because we want to avoid - * doing all of the listening and accepting in the parent - it's - * safer that way. - */ -#ifdef WIN32 - -typedef struct _ThreadList ThreadList; - -struct _ThreadList -{ - HANDLE hThread; - IOCHAN pIOChannel; - ThreadList *pNext; -}; - -static ThreadList *pFirstThread; -static CRITICAL_SECTION Thread_CritSect; -static BOOL bInitialized = FALSE; - -static void ThreadList_Initialize() -{ - /* Initialize the critical Sections */ - InitializeCriticalSection(&Thread_CritSect); - - /* Set the first thraed */ - pFirstThread = NULL; - - /* we have been initialized */ - bInitialized = TRUE; -} - -static void statserv_add(HANDLE hThread, IOCHAN pIOChannel) -{ - /* Only one thread can go through this section at a time */ - EnterCriticalSection(&Thread_CritSect); - - { - /* Lets create our new object */ - ThreadList *pNewThread = (ThreadList *)malloc(sizeof(ThreadList)); - pNewThread->hThread = hThread; - pNewThread->pIOChannel = pIOChannel; - pNewThread->pNext = pFirstThread; - pFirstThread = pNewThread; - - /* Lets let somebody else create a new object now */ - LeaveCriticalSection(&Thread_CritSect); - } -} - -void statserv_remove(IOCHAN pIOChannel) -{ - /* Only one thread can go through this section at a time */ - EnterCriticalSection(&Thread_CritSect); - - { - ThreadList *pCurrentThread = pFirstThread; - ThreadList *pNextThread; - ThreadList *pPrevThread =NULL; - - /* Step through alll the threads */ - for (; pCurrentThread != NULL; pCurrentThread = pNextThread) - { - /* We only need to compare on the IO Channel */ - if (pCurrentThread->pIOChannel == pIOChannel) - { - /* We have found the thread we want to delete */ - /* First of all reset the next pointers */ - if (pPrevThread == NULL) - pFirstThread = pCurrentThread->pNext; - else - pPrevThread->pNext = pCurrentThread->pNext; - - /* All we need todo now is delete the memory */ - free(pCurrentThread); - - /* No need to look at any more threads */ - pNextThread = NULL; - } - else - { - /* We need to look at another thread */ - pNextThread = pCurrentThread->pNext; - pPrevThread = pCurrentThread; - } - } - - /* Lets let somebody else remove an object now */ - LeaveCriticalSection(&Thread_CritSect); - } -} - -/* WIN32 statserv_closedown */ -void statserv_closedown() -{ - /* Shouldn't do anything if we are not initialized */ - if (bInitialized) - { - int iHandles = 0; - HANDLE *pThreadHandles = NULL; - - /* We need to stop threads adding and removing while we */ - /* start the closedown process */ - EnterCriticalSection(&Thread_CritSect); - - { - /* We have exclusive access to the thread stuff now */ - /* Y didn't i use a semaphore - Oh well never mind */ - ThreadList *pCurrentThread = pFirstThread; - - /* Before we do anything else, we need to shutdown the listener */ - if (pListener != NULL) - iochan_destroy(pListener); - - for (; pCurrentThread != NULL; pCurrentThread = pCurrentThread->pNext) - { - /* Just destroy the IOCHAN, that should do the trick */ - iochan_destroy(pCurrentThread->pIOChannel); - closesocket(pCurrentThread->pIOChannel->fd); - - /* Keep a running count of our handles */ - iHandles++; - } - - if (iHandles > 0) - { - HANDLE *pCurrentHandle ; - - /* Allocate the thread handle array */ - pThreadHandles = (HANDLE *)malloc(sizeof(HANDLE) * iHandles); - pCurrentHandle = pThreadHandles; - - for (pCurrentThread = pFirstThread; - pCurrentThread != NULL; - pCurrentThread = pCurrentThread->pNext, pCurrentHandle++) - { - /* Just the handle */ - *pCurrentHandle = pCurrentThread->hThread; - } - } - - /* We can now leave the critical section */ - LeaveCriticalSection(&Thread_CritSect); - } - - /* Now we can really do something */ - if (iHandles > 0) - { - logf (LOG_LOG, "waiting for %d to die", iHandles); - /* This will now wait, until all the threads close */ - WaitForMultipleObjects(iHandles, pThreadHandles, TRUE, INFINITE); - - /* Free the memory we allocated for the handle array */ - free(pThreadHandles); - } - - if (control_block.bend_stop) - (*control_block.bend_stop)(&control_block); - /* No longer require the critical section, since all threads are dead */ - DeleteCriticalSection(&Thread_CritSect); - } -} - -void __cdecl event_loop_thread (IOCHAN iochan) -{ - event_loop (&iochan); -} - -/* WIN32 listener */ -static void listener(IOCHAN h, int event) -{ - COMSTACK line = (COMSTACK) iochan_getdata(h); - association *newas; - int res; - HANDLE newHandle; - - if (event == EVENT_INPUT) - { - if ((res = cs_listen(line, 0, 0)) < 0) - { - yaz_log(LOG_FATAL, "cs_listen failed"); - return; - } - else if (res == 1) - return; - yaz_log(LOG_DEBUG, "listen ok"); - iochan_setevent(h, EVENT_OUTPUT); - iochan_setflags(h, EVENT_OUTPUT | EVENT_EXCEPT); /* set up for acpt */ - } - else if (event == EVENT_OUTPUT) - { - COMSTACK new_line = cs_accept(line); - IOCHAN new_chan; - char *a = NULL; - - if (!new_line) - { - yaz_log(LOG_FATAL, "Accept failed."); - iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); - return; - } - yaz_log(LOG_DEBUG, "Accept ok"); - - if (!(new_chan = iochan_create(cs_fileno(new_line), ir_session, - EVENT_INPUT))) - { - yaz_log(LOG_FATAL, "Failed to create iochan"); - iochan_destroy(h); - return; - } - - yaz_log(LOG_DEBUG, "Creating association"); - if (!(newas = create_association(new_chan, new_line))) - { - yaz_log(LOG_FATAL, "Failed to create new assoc."); - iochan_destroy(h); - return; - } - newas->cs_get_mask = EVENT_INPUT; - newas->cs_put_mask = 0; - newas->cs_accept_mask = 0; - - yaz_log(LOG_DEBUG, "Setting timeout %d", control_block.idle_timeout); - iochan_setdata(new_chan, newas); - iochan_settimeout(new_chan, 60); - - /* Now what we need todo is create a new thread with this iochan as - the parameter */ - newHandle = (HANDLE) _beginthread(event_loop_thread, 0, new_chan); - if (newHandle == (HANDLE) -1) - { - - yaz_log(LOG_FATAL|LOG_ERRNO, "Failed to create new thread."); - iochan_destroy(h); - return; - } - /* We successfully created the thread, so add it to the list */ - statserv_add(newHandle, new_chan); - - yaz_log(LOG_DEBUG, "Created new thread, id = %ld iochan %p",(long) newHandle, new_chan); - iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */ - } - else - { - yaz_log(LOG_FATAL, "Bad event on listener."); - iochan_destroy(h); - return; - } -} - -int statserv_must_terminate(void) -{ - return 0; -} - -#else /* ! WIN32 */ - -static int term_flag = 0; -/* To save having an #ifdef in event_loop we need to - define this empty function -*/ -int statserv_must_terminate(void) -{ - return term_flag; -} - -void statserv_remove(IOCHAN pIOChannel) -{ -} - -void statserv_closedown() -{ - IOCHAN p; - - if (control_block.bend_stop) - (*control_block.bend_stop)(&control_block); - for (p = pListener; p; p = p->next) - { - iochan_destroy(p); - } -} - -void sigterm(int sig) -{ - term_flag = 1; -} - -static void *new_session (void *vp); -static int no_sessions = 0; - -/* UNIX listener */ -static void listener(IOCHAN h, int event) -{ - COMSTACK line = (COMSTACK) iochan_getdata(h); - static int hand[2]; - static int child = 0; - int res; - - if (event == EVENT_INPUT) - { - if (control_block.dynamic && !child) - { - int res; - - ++no_sessions; - if (pipe(hand) < 0) - { - yaz_log(LOG_FATAL|LOG_ERRNO, "pipe"); - iochan_destroy(h); - return; - } - if ((res = fork()) < 0) - { - yaz_log(LOG_FATAL|LOG_ERRNO, "fork"); - iochan_destroy(h); - return; - } - else if (res == 0) /* child */ - { - char nbuf[100]; - IOCHAN pp; - - close(hand[0]); - child = 1; - for (pp = pListener; pp; pp = iochan_getnext(pp)) - { - if (pp != h) - { - COMSTACK l = (COMSTACK)iochan_getdata(pp); - cs_close(l); - iochan_destroy(pp); - } - } - sprintf(nbuf, "%s(%d)", me, getpid()); - yaz_log_init(control_block.loglevel, nbuf, 0); - /* ensure that bend_stop is not called when each child exits - - only for the main process .. - */ - control_block.bend_stop = 0; - } - else /* parent */ - { - close(hand[1]); - /* wait for child to take the call */ - for (;;) - { - char dummy[1]; - int res; - - if ((res = read(hand[0], dummy, 1)) < 0 && - yaz_errno() != EINTR) - { - yaz_log(LOG_FATAL|LOG_ERRNO, "handshake read"); - return; - } - else if (res >= 0) - break; - } - yaz_log(LOG_DEBUG, "P: Child has taken the call"); - close(hand[0]); - return; - } - } - if ((res = cs_listen_check(line, 0, 0, control_block.check_ip, - control_block.daemon_name)) < 0) - { - yaz_log(LOG_WARN|LOG_ERRNO, "cs_listen failed"); - return; - } - else if (res == 1) - return; - yaz_log(LOG_DEBUG, "listen ok"); - iochan_setevent(h, EVENT_OUTPUT); - iochan_setflags(h, EVENT_OUTPUT | EVENT_EXCEPT); /* set up for acpt */ - } - /* in dynamic mode, only the child ever comes down here */ - else if (event == EVENT_OUTPUT) - { - COMSTACK new_line = cs_accept(line); - - if (!new_line) - { - yaz_log(LOG_FATAL, "Accept failed."); - iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */ - return; - } - yaz_log(LOG_DEBUG, "accept ok"); - if (control_block.dynamic) - { - IOCHAN pp; - /* close our half of the listener socket */ - for (pp = pListener; pp; pp = iochan_getnext(pp)) - { - COMSTACK l = (COMSTACK)iochan_getdata(pp); - cs_close(l); - iochan_destroy(pp); - } - /* release dad */ - yaz_log(LOG_DEBUG, "Releasing parent"); - close(hand[1]); - } - else - { - iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */ - ++no_sessions; - } -#if YAZ_POSIX_THREADS - if (control_block.threads) - { - pthread_t child_thread; - pthread_create (&child_thread, 0, new_session, new_line); - pthread_detach (child_thread); - } - else - new_session(new_line); -#elif YAZ_GNU_THREADS - if (control_block.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 (LOG_LOG, "pth_spawn begin"); - child_thread = pth_spawn (attr, new_session, new_line); - yaz_log (LOG_LOG, "pth_spawn finish"); - pth_attr_destroy (attr); - } - else - new_session(new_line); -#else - new_session(new_line); -#endif - } - else if (event == EVENT_TIMEOUT) - { - yaz_log(LOG_LOG, "Shutting down listener."); - iochan_destroy(h); - } - else - { - yaz_log(LOG_FATAL, "Bad event on listener."); - iochan_destroy(h); - } -} - -static void *new_session (void *vp) -{ - char *a; - association *newas; - IOCHAN new_chan; - COMSTACK new_line = (COMSTACK) vp; - - 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); - - if (mask) - { - cs_accept_mask = mask; /* accept didn't complete */ - cs_get_mask = 0; - } - else - { - cs_accept_mask = 0; /* accept completed. */ - cs_get_mask = mask = EVENT_INPUT; - } - - if (!(new_chan = iochan_create(cs_fileno(new_line), ir_session, mask))) - { - yaz_log(LOG_FATAL, "Failed to create iochan"); - return 0; - } - if (!(newas = create_association(new_chan, new_line))) - { - yaz_log(LOG_FATAL, "Failed to create new assoc."); - return 0; - } - newas->cs_accept_mask = cs_accept_mask; - newas->cs_get_mask = cs_get_mask; - - iochan_setdata(new_chan, newas); - iochan_settimeout(new_chan, 60); -#if 1 - a = cs_addrstr(new_line); -#else - a = 0; -#endif - yaz_log(LOG_LOG, "Starting session %d from %s", - no_sessions, a ? a : "[Unknown]"); - if (max_sessions && no_sessions == max_sessions) - control_block.one_shot = 1; - if (control_block.threads) - { - event_loop(&new_chan); - } - else - { - new_chan->next = pListener; - pListener = new_chan; - } - return 0; -} - -/* UNIX */ -#endif - -static void inetd_connection(int what) -{ - COMSTACK line; - IOCHAN chan; - association *assoc; - char *addr; - - if ((line = cs_createbysocket(0, tcpip_type, 0, what))) - { - if ((chan = iochan_create(cs_fileno(line), ir_session, EVENT_INPUT))) - { - if ((assoc = create_association(chan, line))) - { - iochan_setdata(chan, assoc); - iochan_settimeout(chan, 60); - addr = cs_addrstr(line); - yaz_log(LOG_LOG, "Inetd association from %s", - addr ? addr : "[UNKNOWN]"); - assoc->cs_get_mask = EVENT_INPUT; - } - else - { - yaz_log(LOG_FATAL, "Failed to create association structure"); - } - chan->next = pListener; - pListener = chan; - } - else - { - yaz_log(LOG_FATAL, "Failed to create iochan"); - } - } - else - { - yaz_log(LOG_ERRNO|LOG_FATAL, "Failed to create comstack on socket 0"); - } -} - -/* - * Set up a listening endpoint, and give it to the event-handler. - */ -static int add_listener(char *where, int what) -{ - COMSTACK l; - void *ap; - IOCHAN lst = NULL; - const char *mode; - - if (control_block.dynamic) - mode = "dynamic"; - else if (control_block.threads) - mode = "threaded"; - else - mode = "static"; - - yaz_log(LOG_LOG, "Adding %s %s listener on %s", mode, - what == PROTO_SR ? "SR" : "Z3950", where); - - l = cs_create_host(where, 0, &ap); - if (!l) - { - yaz_log(LOG_FATAL|LOG_ERRNO, "Failed to listen on %s", where); - return -1; - } - if (cs_bind(l, ap, CS_SERVER) < 0) - { - yaz_log(LOG_FATAL|LOG_ERRNO, "Failed to bind to %s", where); - cs_close (l); - return -1; - } - if (!(lst = iochan_create(cs_fileno(l), listener, EVENT_INPUT | - EVENT_EXCEPT))) - { - yaz_log(LOG_FATAL|LOG_ERRNO, "Failed to create IOCHAN-type"); - cs_close (l); - return -1; - } - iochan_setdata(lst, l); - - /* Ensure our listener chain is setup properly */ - lst->next = pListener; - pListener = lst; - return 0; /* OK */ -} - -#ifndef WIN32 -/* UNIX only (for windows we don't need to catch the signals) */ -static void catchchld(int num) -{ - while (waitpid(-1, 0, WNOHANG) > 0) - ; - signal(SIGCHLD, catchchld); -} -#endif - -statserv_options_block *statserv_getcontrol(void) -{ - static statserv_options_block cb; - - memcpy(&cb, &control_block, sizeof(cb)); - return &cb; -} - -void statserv_setcontrol(statserv_options_block *block) -{ - memcpy(&control_block, block, sizeof(*block)); -} - -static void statserv_reset(void) -{ -} - -int statserv_start(int argc, char **argv) -{ - int ret; - -#ifdef WIN32 - /* We need to initialize the thread list */ - ThreadList_Initialize(); -/* WIN32 */ -#endif - -#ifdef WIN32 - if ((me = strrchr (argv[0], '\\'))) - me++; - else - me = argv[0]; -#else - me = argv[0]; -#endif - if (control_block.options_func(argc, argv)) - return(1); - - if (control_block.bend_start) - (*control_block.bend_start)(&control_block); -#ifdef WIN32 - yaz_log (LOG_LOG, "Starting server %s", me); -#else -/* UNIX */ - if (control_block.inetd) - inetd_connection(control_block.default_proto); - else - { - yaz_log (LOG_LOG, "Starting server %s pid=%d", me, getpid()); -#if 0 - sigset_t sigs_to_block; - - sigemptyset(&sigs_to_block); - sigaddset (&sigs_to_block, SIGTERM); - pthread_sigmask (SIG_BLOCK, &sigs_to_block, 0); - /* missing... */ -#endif - if (control_block.dynamic) - signal(SIGCHLD, catchchld); - } - signal (SIGPIPE, SIG_IGN); - signal (SIGTERM, sigterm); - if (*control_block.setuid) - { - struct passwd *pw; - - if (!(pw = getpwnam(control_block.setuid))) - { - yaz_log(LOG_FATAL, "%s: Unknown user", control_block.setuid); - return(1); - } - if (setuid(pw->pw_uid) < 0) - { - yaz_log(LOG_FATAL|LOG_ERRNO, "setuid"); - exit(1); - } - } -/* UNIX */ -#endif - - - if ((pListener == NULL) && *control_block.default_listen) - add_listener(control_block.default_listen, - control_block.default_proto); - - if (pListener == NULL) - ret = 1; - else - { - yaz_log(LOG_LOG, "Entering event loop."); - ret = event_loop(&pListener); - } - return ret; -} - -int check_options(int argc, char **argv) -{ - int ret = 0, r; - char *arg; - - while ((ret = options("1a:iszSTl:v:u:c:w:t:k:d:D:", argv, argc, &arg)) != -2) - { - switch (ret) - { - case 0: - if (add_listener(arg, control_block.default_proto)) - return 1; /* failed to create listener */ - break; - case '1': - control_block.one_shot = 1; - control_block.dynamic = 0; - break; - case 'z': - control_block.default_proto = PROTO_Z3950; - break; - case 's': - fprintf (stderr, "%s: SR protocol no longer supported\n", me); - exit (1); - break; - case 'S': - control_block.dynamic = 0; - break; - case 'T': -#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; -#endif - break; - case 'l': - strcpy(control_block.logfile, arg ? arg : ""); - yaz_log_init(control_block.loglevel, me, control_block.logfile); - break; - case 'v': - control_block.loglevel = yaz_log_mask_str(arg); - yaz_log_init(control_block.loglevel, me, control_block.logfile); - break; - case 'a': - strcpy(control_block.apdufile, arg ? arg : ""); - break; - case 'u': - strcpy(control_block.setuid, arg ? arg : ""); - break; - case 'c': - strcpy(control_block.configname, arg ? arg : ""); - break; - case 'd': - strcpy(control_block.daemon_name, arg ? arg : ""); - break; - case 't': - if (!arg || !(r = atoi(arg))) - { - fprintf(stderr, "%s: Specify positive timeout for -t.\n", me); - return(1); - } - control_block.idle_timeout = r; - break; - case 'k': - if (!arg || !(r = atoi(arg))) - { - fprintf(stderr, "%s: Specify positive size for -k.\n", me); - return(1); - } - control_block.maxrecordsize = r * 1024; - break; - case 'i': - control_block.inetd = 1; - break; - case 'w': - if (chdir(arg)) - { - perror(arg); - return 1; - } - break; - case 'D': - max_sessions = atoi(arg); - break; - default: - fprintf(stderr, "Usage: %s [ -a -v " - " -l -u -c -t " - " -k -d " - " -ziST1 -w ... ]\n", me); - return 1; - } - } - return 0; -} - -#ifdef WIN32 -typedef struct _Args -{ - char **argv; - int argc; -} Args; - -static Args ArgDetails; - -/* name of the executable */ -#define SZAPPNAME "server" - -/* list of service dependencies - "dep1\0dep2\0\0" */ -#define SZDEPENDENCIES "" - -int statserv_main(int argc, char **argv, - bend_initresult *(*bend_init)(bend_initrequest *r), - void (*bend_close)(void *handle)) -{ - statserv_options_block *cb = statserv_getcontrol(); - - cb->bend_init = bend_init; - cb->bend_close = bend_close; - - statserv_setcontrol(cb); - - /* Lets setup the Arg structure */ - ArgDetails.argc = argc; - ArgDetails.argv = argv; - - /* Now setup the service with the service controller */ - SetupService(argc, argv, &ArgDetails, SZAPPNAME, - cb->service_name, /* internal service name */ - cb->service_display_name, /* displayed name */ - SZDEPENDENCIES); - return 0; -} - -int StartAppService(void *pHandle, int argc, char **argv) -{ - /* Initializes the App */ - return 1; -} - -void RunAppService(void *pHandle) -{ - Args *pArgs = (Args *)pHandle; - - /* Starts the app running */ - statserv_start(pArgs->argc, pArgs->argv); -} - -void StopAppService(void *pHandle) -{ - /* Stops the app */ - statserv_closedown(); - statserv_reset(); -} -/* WIN32 */ -#else -/* UNIX */ -int statserv_main(int argc, char **argv, - bend_initresult *(*bend_init)(bend_initrequest *r), - void (*bend_close)(void *handle)) -{ - int ret; - statserv_options_block *cb = statserv_getcontrol(); - - cb->bend_init = bend_init; - cb->bend_close = bend_close; - - statserv_setcontrol(cb); - ret = statserv_start (argc, argv); - statserv_closedown (); - statserv_reset(); - return ret; -} -#endif