miniserv...

"Paul Ingram" <[email protected]>
Newsgroups gmane.comp.lib.libwww
Message-ID <[email protected]>
Hello,

I am trying to put together a fast and flexible XML-RPC server.
I am basing my application on the libwww, Epinions XML-RPC libraries.
and the expat XML parser. It has been a steep learning curve and I
am not there yet.

So far I have:-

built a static library of libwww libraries - I can now listen using this library.
picked up and built the latest expat release
built the Epinions work into a static library.

This is (sadly) under Windows and (thankfully) Borland C++ Builder 5.

I would find a recent port of the old miniserv program to the
current release of libwww extremely helpful, especially if some
kind soul has taken it to Windows aswell. It seems a lot has
changed since the 4.0D release of MiniServe.

4.0D bits attached...

Best Regards, Paul.

Paul Ingram Group Ltd           email: [email protected]
140A High Street                   tel: +44 1483 862860
Godalming                             fax: +44 1483 862801
Surrey,                                  www.ig.co.uk
GU7 1AB United Kingdom    www.sitedirector.org
HTServer.h (application/octet-stream, 928 B)
/*                                                                            W3C Mini Server
                                     W3C MINI SERVER
                                             
 */
/*
**      (c) COPYRIGHT MIT 1995.
**      Please first read the full copyright statement in the file COPYRIGH.
*/
/*

   The W3C Mini Server is a very simple cross platform, non-forking server. It is
   developed as a test tool for the W3C Reference Library.
   
   The module is implemented by HTServer.c, and it is a part of the W3C Mini Server.
   
 */
#ifndef HTSERVER_H
#define HTSERVER_H
/*

 */

typedef WORD SockOps;

 #if WWWTRACE_MODE == WWWTRACE_TTY
#define STDOUT 1
#define OUTPUT 2        /* used in TTYPrint's switch for output multiplexing */
#else
#define STDOUT stdout
#define OUTPUT stdout    /* output is a global target for output redirection */
#endif
/*

 */
#endif /* HTSERVER_H */
/* End of Declaration */
HTServer.c (application/octet-stream, 12.1 KB)
/*         		    					     HTServer.c
**	MINI SERVER
**
**	(c) COPRIGHT MIT 1995.
**	Please first read the full copyright statement in the file COPYRIGH.
**
**  Authors:
**	HFN		Henrik Frystyk Nielsen ([email protected])
**
**  History:
**	Nov 24 95	First version
*/

#include "WWWLib.h"			      /* Global Library Include file */
#include "WWWApp.h"
#include "WWWMIME.h"
#include "WWWHTTP.h"
#include "WWWFile.h"
#include "WWWRules.h"

#include "HTBInit.h"

#include "HTServer.h"					 /* Implemented here */

#ifndef VS
#define VS "unspecified"
#endif

#define APP_NAME		"W3CMiniServer"
#define APP_VERSION		VS

/* Default page for "-help" command line option */
#define HELP	"http://www.w3.org/pub/WWW/MiniServ/User/CommandLine.html"

#define DEFAULT_OUTPUT_FILE	"web.out"
#define DEFAULT_RULE_FILE	"web.conf"
#define DEFAULT_LOG_FILE       	"web.log"

#define DEFAULT_PORT		80

#define DEFAULT_TIMEOUT		120		       /* timeout in seconds */

#define DEFAULT_FORMAT		WWW_SOURCE

#define DEFAULT_BACKLOG		HT_BACKLOG

#define DEFAULT_ACCEPT		-1

#if defined(__svr4__)
#define CATCH_SIG
#endif

typedef enum _MSFlags {
    MS_PREEMPTIVE=0x1
} MSFlags;

typedef struct _MiniServ {
    HTRequest *		request;
    HTParentAnchor *	anchor;
    HTList *		active;			  /* List of active requests */
    SOCKET		port;
    struct timeval *	tv;				/* Timeout on socket */
    HTList *		converters;
    int			backlog;		       /* Backlog for listen */
    int			accept;		/* Total accepted connections served */
    char *		cwd;				  /* Current dir URL */
    char *		rules;
    char *		logfile;
    MSFlags		flags;
} MiniServ;


/* ------------------------------------------------------------------------- */

/*	Create a Mini Server Object
**	---------------------------
*/
PRIVATE MiniServ * MiniServ_new (void)
{
    MiniServ * me;
    if ((me = (MiniServ *) calloc(1, sizeof(MiniServ))) == NULL ||
	(me->tv = (struct timeval*) calloc(1, sizeof(struct timeval))) == NULL)
	outofmem(__FILE__, "MiniServ_new");
    me->tv->tv_sec = DEFAULT_TIMEOUT;
    me->cwd = HTFindRelatedName();

    /* Bind the MiniServ object together with the Request Object */
    me->request = HTRequest_new();
    me->active = HTList_new();
    HTList_addObject(me->active, me->request);
    me->port = DEFAULT_PORT;
    me->backlog = DEFAULT_BACKLOG;
    me->accept = DEFAULT_ACCEPT;

    /* Set default values in request object */
    HTRequest_setGnHd(me->request, HT_G_DATE);
    HTRequest_setOutputFormat(me->request, DEFAULT_FORMAT);
    HTRequest_setContext(me->request, me);
    return me;
}

/*	Delete a Mini Server Object
**	---------------------------
*/
PRIVATE BOOL MiniServ_delete (MiniServ * me)
{
    if (me) {
	HTRequest_delete(me->request);
	if (me->logfile) HTLog_close();
	HTList_delete(me->active);
	HT_FREE(me->cwd);
	HT_FREE(me->tv);
	HT_FREE(me);
	return YES;
    }
    return NO;
}

PRIVATE void Cleanup (MiniServ * me, int status)
{
    HTNet_killAll();
    MiniServ_delete(me);
    HTLibTerminate();
#ifdef VMS
    exit(status ? status : 1);
#else
    exit(status ? status : 0);
#endif
}


#ifdef CATCH_SIG
#include <signal.h>
/*								    SetSignal
**  This function sets up signal handlers. This might not be necessary to
**  call if the application has its own handlers.
*/
PRIVATE void SetSignal (void)
{
    /* On some systems (SYSV) it is necessary to catch the SIGPIPE signal
    ** when attemting to connect to a remote host where you normally should
    ** get `connection refused' back
    */
    if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
	if (WWWTRACE) TTYPrint(TDEST, "HTSignal.... Can't catch SIGPIPE\n");
    } else {
	if (WWWTRACE) TTYPrint(TDEST, "HTSignal.... Ignoring SIGPIPE\n");
    }
}
#endif /* CATCH_SIG */

PRIVATE void VersionInfo (void)
{
    TTYPrint(OUTPUT,"\n\nW3C Reference Software\n\n");
    TTYPrint(OUTPUT,"\tW3C W3C Mini Server (%s) version %s.\n",
	     APP_NAME, APP_VERSION);
    TTYPrint(OUTPUT,"\tW3C Reference Library version %s.\n\n",HTLib_version());
    TTYPrint(OUTPUT,"Please send feedback to <[email protected]>\n");
}

/*	timeout_handler
**	---------------
**	This function is registered to handle timeout in select eventloop
*/
PRIVATE int timeout_handler (HTRequest * request)
{
    TTYPrint(TDEST, "Request timeout... We don't know how tow handle this yet :-(\n");
    HTRequest_kill(request);
    return 0;
}

/*	header_handler
**	---------------
**	This function is registered to handle unknown MIME headers
*/
PRIVATE int header_handler (HTRequest * request, CONST char * token)
{
    if (WWWTRACE) TTYPrint(TDEST, "Parsing unknown header `%s\'\n", token);
    return HT_OK;
}

/*	server_handler
**	---------------
**	Is called if we get a read notification on server port
*/
PRIVATE int server_handler (SOCKET master, HTRequest * request, SockOps ops)
{
    MiniServ * ms = (MiniServ *) HTRequest_context(request);
    if (WWWTRACE) TTYPrint(TDEST, "Accepting... socket %d\n", master);
    if (ms->accept>0) ms->accept--;
    if (ops == FD_READ) {
	HTRequest * server = HTRequest_dup(request);
	HTList_addObject(ms->active, server);
	HTNet_newServer(server, master, "http");
	return HT_OK;
    }
    return HT_ERROR;
}

/*	terminate_handler
**	-----------------
**	Is called whenever a request has terminated
*/
PRIVATE int terminate_handler (HTRequest * request, int status)
{
    MiniServ * ms = (MiniServ *) HTRequest_context(request);
    if (WWWTRACE) TTYPrint(TDEST, "SERVER...... %p ended with status %d\n",
			   request, status);
    if (HTLog_isOpen()) HTLog_add(request, status);
    HTRequest_delete(request);
    if (!ms->accept) {
	TTYPrint(TDEST,"SERVER...... Done - stopping\n");
	Cleanup(ms, 0);
    }
    return HT_OK;
}

/* ------------------------------------------------------------------------- */
/*				  MAIN PROGRAM				     */
/* ------------------------------------------------------------------------- */

int main (int argc, char ** argv)
{    
    int		arg;
    MiniServ *	ms = MiniServ_new();

    /* Starts Mac GUSI socket library */
#ifdef GUSI				   /* Starts Mac GUSI socket library */
    GUSISetup(GUSIwithSIOUXSockets);
    GUSISetup(GUSIwithInternetSockets);
#endif

    /* Initiate W3C Reference Library */
    HTLibInit(APP_NAME, APP_VERSION);

    /* Initialize the protocol modules */
    HTProtocol_add("http", NO, HTLoadHTTP, HTServHTTP);
#if 0
    HTProtocol_add("file", NO, HTLoadFile, NULL);
#endif

    /* Initialize set of converters */
    ms->converters = HTList_new();
    HTConversion_add(ms->converters, "message/x-rfc822-head",
		     "*/*", HTMIMEHeader, 1.0, 0.0, 0.0);
    HTConversion_add(ms->converters, "message/rfc822",
		     "*/*", HTMIMEConvert, 1.0, 0.0, 0.0);
    HTConversion_add(ms->converters, "multipart/*",
		     "*/*", HTBoundary,  1.0, 0.0, 0.0);
    HTFormat_setConversion(ms->converters);

    /* Initialize bindings between file suffixes and media types */
    HTFileInit();

    /* Get any proxy or gateway environment variables */
    HTProxy_getEnvVar();

    /* Register call back functions for the Net Manager */
    HTNetCall_addBefore(HTLoadStart, 0);

    /* Scan command Line for parameters */
    for (arg=1; arg<argc ; arg++) {
	if (*argv[arg] == '-') {

	    /* -? or -help: show the command line help page */
	    if (!strcmp(argv[arg],"-?") || !strcmp(argv[arg],"-help")) {
		ms->anchor = (HTParentAnchor *) HTAnchor_findAddress(HELP);

	    /* log file */
	    } else if (!strcmp(argv[arg], "-l")) {
		ms->logfile = (arg+1 < argc && *argv[arg+1] != '-') ?
		    argv[++arg] : DEFAULT_LOG_FILE;

	    /* rule file */
	    } else if (!strcmp(argv[arg], "-r")) {
		ms->rules = (arg+1 < argc && *argv[arg+1] != '-') ?
		    argv[++arg] : DEFAULT_RULE_FILE;

	    /* preemptive or non-preemptive access */
	    } else if (!strcmp(argv[arg], "-single")) {
		HTRequest_setPreemptive(ms->request, YES);
		ms->flags |= MS_PREEMPTIVE;

	    /* timeout -- Change the default request timeout */
	    } else if (!strcmp(argv[arg], "-timeout")) {
		int timeout = (arg+1 < argc && *argv[arg+1] != '-') ?
		    atoi(argv[++arg]) : DEFAULT_TIMEOUT;
		if (timeout > 0) ms->tv->tv_sec = timeout;

	    /* server port */
	    } else if (!strncmp(argv[arg], "-p", 2)) { 
		ms->port = (arg+1 < argc && *argv[arg+1] != '-') ?
		    atoi(argv[++arg]) : DEFAULT_PORT;

	    /* backlog for listen() */
	    } else if (!strcmp(argv[arg], "-backlog")) { 
		ms->backlog = (arg+1 < argc && *argv[arg+1] != '-') ?
		    atoi(argv[++arg]) : DEFAULT_BACKLOG;

	    /* Total number of accepted connections to be served */
	    } else if (!strcmp(argv[arg], "-accept")) { 
		ms->accept = (arg+1 < argc && *argv[arg+1] != '-') ?
		    atoi(argv[++arg]) : DEFAULT_ACCEPT;

	    /* directory listings */
	    } else if (!strncmp(argv[arg], "-d", 2)) {
		char *p = argv[arg]+2;
		for(;*p;p++) {
		    switch (argv[arg][2]) {
		      case 'r':HTFile_setDirReadme(HT_DIR_README_NONE); break;
		      case 't':HTFile_setDirReadme(HT_DIR_README_TOP); break;
		      case 'b':HTFile_setDirReadme(HT_DIR_README_BOTTOM);break;
		      case 'n':HTFile_setDirAccess(HT_DIR_FORBID); break;
		      case 's':HTFile_setDirAccess(HT_DIR_SELECTIVE); break;
		      case 'y':HTFile_setDirAccess(HT_DIR_OK); break;
		      default:
			if (WWWTRACE)
			    TTYPrint(TDEST,"Bad parameter (%s) in -d option\n",
				     argv[arg]);
		    }
		}

	    /* Print version and exit */
	    } else if (!strcmp(argv[arg], "-version")) { 
		VersionInfo();
		Cleanup(ms, 0);
		
#ifdef WWWTRACE
	    /* trace flags */
	    } else if (!strncmp(argv[arg], "-v", 2)) {
		char *p = argv[arg]+2;
		WWWTRACE = 0;
		for(; *p; p++) {
		    switch (*p) {
		      case 'a': WWWTRACE |= SHOW_ANCHOR_TRACE; break;
		      case 'b': WWWTRACE |= SHOW_BIND_TRACE; break;
		      case 'c': WWWTRACE |= SHOW_CACHE_TRACE; break;
		      case 'g': WWWTRACE |= SHOW_SGML_TRACE; break;
		      case 'p': WWWTRACE |= SHOW_PROTOCOL_TRACE; break;
		      case 's': WWWTRACE |= SHOW_STREAM_TRACE; break;
		      case 't': WWWTRACE |= SHOW_THREAD_TRACE; break;
		      case 'u': WWWTRACE |= SHOW_URI_TRACE; break;
		      default:
			if (WWWTRACE)
			    TTYPrint(TDEST,"Bad parameter (%s) in -v option\n",
				     argv[arg]);
		    }
		}
		if (!WWWTRACE) WWWTRACE = SHOW_ALL_TRACE;
#endif
	    } else {
		if (WWWTRACE) TTYPrint(TDEST, "Bad Argument (%s)\n",argv[arg]);
	    }
        } else {
	    if (WWWTRACE) TTYPrint(TDEST, "Bad Argument (%s)\n",argv[arg]);
	}
    }
	
#ifdef CATCH_SIG
    SetSignal();
#endif

    /* Register our User Prompts etc in the Alert Manager */
    HTAlert_add(HTError_response, HT_A_MESSAGE);

    /* Register a call back function for the Net Manager */
    HTNetCall_addAfter(terminate_handler, HT_ALL);
    
    /* Register our own MIME header handler for extra headers */
    HTHeader_addParser("*", NO, header_handler);

    /* Set timeout on sockets */
    HTEvent_registerTimeout(ms->tv, ms->request, timeout_handler, NO);

    /* Set max number of sockets we want open simultanously */
    HTNet_setMaxSocket(32);

    /* Rule file specified? */
    if (ms->rules) {
	HTList * list = HTList_new();
	HTRequest * rr = HTRequest_new();
	char * rules = HTParse(ms->rules, ms->cwd, PARSE_ALL);
	HTParentAnchor * ra = (HTParentAnchor *) HTAnchor_findAddress(rules);
	HTRequest_setPreemptive(rr, YES);
	HTConversion_add(list, "application/x-www-rules", "*/*", HTRules,
			 1.0, 0.0, 0.0);
	HTRequest_setConversion(rr, list, YES);
	if (HTLoadAnchor((HTAnchor *) ra, rr) != YES)
	    if (WWWTRACE) TTYPrint(TDEST, "Can't access rules\n");
	HTConversion_deleteAll(list);
	HTRequest_delete(rr);
	HT_FREE(rules);
    }

    /* Log file specifed? */
    if (ms->logfile) HTLog_open(ms->logfile, YES, YES);

    /* Set up a server to listen on this port */
    if (ms->port >= 0) {
	HTNet * net = HTNet_new(ms->request, ms->port);

	/* Start listening on the socket */
 	if (net && HTDoListen(net, ms->port, INVSOC, ms->backlog) == HT_OK) {

	    /* Register a callback function for handling a request */
	    HTEvent_Register(HTNet_socket(net), ms->request, (SockOps) FD_READ,
			     server_handler, HT_PRIORITY_MAX);
	} else {
	    if (WWWTRACE) TTYPrint(TDEST,"Can't listen on port %d\n",ms->port);
	    Cleanup(ms, -1);
	}
    }

    /* Go into the event loop... */
    HTEvent_Loop(ms->request);

    /* Only gets here if event loop fails */
    Cleanup(ms, 0);
    return 0;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.