Remove (Moved to cpukit/http).

This commit is contained in:
Ralf Corsepius
2004-10-27 06:08:56 +00:00
parent cc870803f9
commit f1959d65e2
49 changed files with 0 additions and 23576 deletions

View File

@@ -1,2 +0,0 @@
Makefile
Makefile.in

View File

@@ -1,97 +0,0 @@
##
## $Id$
##
include $(top_srcdir)/automake/compile.am
EXTRA_LIBRARIES =
CLEANFILES =
AM_CPPFLAGS += -DWEBS -DUEMF -DOS="RTEMS"
if HAS_NETWORKING
if HAS_POSIX
include_goaheaddir = $(includedir)/goahead
include_HEADERS = rtems_webserver.h
include_goahead_HEADERS = ej.h ejIntrn.h emfdb.h md5.h uemf.h um.h webs.h \
wsIntrn.h
EXTRA_LIBRARIES += libhttpd.a
CLEANFILES += libhttpd.a
libhttpd_a_SOURCES = asp.c balloc.c default.c ejlex.c ejparse.c emfdb.c \
form.c h.c handler.c md5c.c mime.c misc.c webpage.c ringq.c rom.c \
security.c sock.c socket.c sym.c uemf.c um.c url.c value.c wbase64.c \
webrom.c webs.c websuemf.c webmain.c
libhttpd_a_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAGS_OPTIMIZE_V)
EXTRA_LIBRARIES += libhttpd_g.a
CLEANFILES += libhttpd_g.a
libhttpd_g_a_SOURCES = $(libhttpd_a_SOURCES)
libhttpd_g_a_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAGS_DEBUG_V)
noinst_DATA = libhttpd$(LIB_VARIANT).a
endif
endif
all-local: $(PREINSTALL_FILES)
EXTRA_DIST = webcomp.c webpage.c
PREINSTALL_DIRS =
PREINSTALL_FILES =
$(PROJECT_INCLUDE)/$(dirstamp):
@$(mkdir_p) $(PROJECT_INCLUDE)
@: > $(PROJECT_INCLUDE)/$(dirstamp)
PREINSTALL_DIRS += $(PROJECT_INCLUDE)/$(dirstamp)
if HAS_NETWORKING
if HAS_POSIX
$(PROJECT_INCLUDE)/goahead/$(dirstamp):
@$(mkdir_p) $(PROJECT_INCLUDE)/goahead
@: > $(PROJECT_INCLUDE)/goahead/$(dirstamp)
PREINSTALL_DIRS += $(PROJECT_INCLUDE)/goahead/$(dirstamp)
$(PROJECT_INCLUDE)/rtems_webserver.h: rtems_webserver.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems_webserver.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems_webserver.h
$(PROJECT_INCLUDE)/goahead/ej.h: ej.h $(PROJECT_INCLUDE)/goahead/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/goahead/ej.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/goahead/ej.h
$(PROJECT_INCLUDE)/goahead/ejIntrn.h: ejIntrn.h $(PROJECT_INCLUDE)/goahead/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/goahead/ejIntrn.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/goahead/ejIntrn.h
$(PROJECT_INCLUDE)/goahead/emfdb.h: emfdb.h $(PROJECT_INCLUDE)/goahead/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/goahead/emfdb.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/goahead/emfdb.h
$(PROJECT_INCLUDE)/goahead/md5.h: md5.h $(PROJECT_INCLUDE)/goahead/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/goahead/md5.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/goahead/md5.h
$(PROJECT_INCLUDE)/goahead/uemf.h: uemf.h $(PROJECT_INCLUDE)/goahead/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/goahead/uemf.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/goahead/uemf.h
$(PROJECT_INCLUDE)/goahead/um.h: um.h $(PROJECT_INCLUDE)/goahead/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/goahead/um.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/goahead/um.h
$(PROJECT_INCLUDE)/goahead/webs.h: webs.h $(PROJECT_INCLUDE)/goahead/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/goahead/webs.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/goahead/webs.h
$(PROJECT_INCLUDE)/goahead/wsIntrn.h: wsIntrn.h $(PROJECT_INCLUDE)/goahead/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/goahead/wsIntrn.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/goahead/wsIntrn.h
endif
endif
CLEANFILES += $(PREINSTALL_FILES)
DISTCLEANFILES = $(PREINSTALL_DIRS)
include $(top_srcdir)/automake/local.am

View File

@@ -1,36 +0,0 @@
#
# $Id$
#
Notes on merging GoAhead Webs 2.1.4. Eventually RTEMS should be supported
in their distributions and this directory removed.
Applied patch from Antti P Miettinen <antti.p.miettinen@nokia.com>.
Obtain the original distribution from http://www.goahead.com for
documentation.
Porting
=======
- added rtems complier flags to uemf.h and misc.c
- following source files are distributed with the web server
but not currently used by RTEMS
[cgi.c, sockGen.c, umui.c, websSSL.c, websda.c]
Tailoring
=========
socket.c is RTEMS specific
Renames
=======
Distributed as This Directory
============== ================
base64.c wbase64.c
page.c webpage.c
RTEMS Specific Additions
========================
webmain.c
rtems_webserver.h

View File

@@ -1,321 +0,0 @@
/*
* asp.c -- Active Server Page Support
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* The ASP module processes ASP pages and executes embedded scripts. It
* support an open scripting architecture with in-built support for
* Ejscript(TM).
*/
/********************************* Includes ***********************************/
#include "wsIntrn.h"
/********************************** Locals ************************************/
static sym_fd_t websAspFunctions = -1; /* Symbol table of functions */
static int aspOpenCount = 0; /* count of apps using this module */
/***************************** Forward Declarations ***************************/
static char_t *strtokcmp(char_t *s1, char_t *s2);
static char_t *skipWhite(char_t *s);
/************************************* Code ***********************************/
/*
* Create script spaces and commands
*/
int websAspOpen()
{
if (++aspOpenCount == 1) {
/*
* Create the table for ASP functions
*/
websAspFunctions = symOpen(WEBS_SYM_INIT * 2);
/*
* Create standard ASP commands
*/
websAspDefine(T("write"), websAspWrite);
}
return 0;
}
/************************************* Code ***********************************/
/*
* Close Asp symbol table.
*/
void websAspClose()
{
if (--aspOpenCount <= 0) {
if (websAspFunctions != -1) {
symClose(websAspFunctions);
websAspFunctions = -1;
}
}
}
/******************************************************************************/
/*
* Process ASP requests and expand all scripting commands. We read the
* entire ASP page into memory and then process. If you have really big
* documents, it is better to make them plain HTML files rather than ASPs.
*/
int websAspRequest(webs_t wp, char_t *lpath)
{
websStatType sbuf;
char *rbuf;
char_t *token, *lang, *result, *path, *ep, *cp, *buf, *nextp;
char_t *last;
int rc, engine, len, ejid;
a_assert(websValid(wp));
a_assert(lpath && *lpath);
rc = -1;
buf = NULL;
rbuf = NULL;
engine = EMF_SCRIPT_EJSCRIPT;
wp->flags |= WEBS_HEADER_DONE;
path = websGetRequestPath(wp);
/*
* Create Ejscript instance in case it is needed
*/
ejid = ejOpenEngine(wp->cgiVars, websAspFunctions);
if (ejid < 0) {
websError(wp, 200, T("Can't create Ejscript engine"));
goto done;
}
ejSetUserHandle(ejid, (int) wp);
if (websPageStat(wp, lpath, path, &sbuf) < 0) {
websError(wp, 200, T("Can't stat %s"), lpath);
goto done;
}
/*
* Create a buffer to hold the ASP file in-memory
*/
len = sbuf.size * sizeof(char);
if ((rbuf = balloc(B_L, len + 1)) == NULL) {
websError(wp, 200, T("Can't get memory"));
goto done;
}
rbuf[len] = '\0';
if (websPageReadData(wp, rbuf, len) != len) {
websError(wp, 200, T("Cant read %s"), lpath);
goto done;
}
websPageClose(wp);
/*
* Convert to UNICODE if necessary.
*/
if ((buf = ballocAscToUni(rbuf, len)) == NULL) {
websError(wp, 200, T("Can't get memory"));
goto done;
}
/*
* Scan for the next "<%"
*/
last = buf;
rc = 0;
while (rc == 0 && *last && ((nextp = gstrstr(last, T("<%"))) != NULL)) {
websWriteBlock(wp, last, (nextp - last));
nextp = skipWhite(nextp + 2);
/*
* Decode the language
*/
token = T("language");
if ((lang = strtokcmp(nextp, token)) != NULL) {
if ((cp = strtokcmp(lang, T("=javascript"))) != NULL) {
engine = EMF_SCRIPT_EJSCRIPT;
} else {
cp = nextp;
}
nextp = cp;
}
/*
* Find tailing bracket and then evaluate the script
*/
if ((ep = gstrstr(nextp, T("%>"))) != NULL) {
*ep = '\0';
last = ep + 2;
nextp = skipWhite(nextp);
/*
* Handle backquoted newlines
*/
for (cp = nextp; *cp; ) {
if (*cp == '\\' && (cp[1] == '\r' || cp[1] == '\n')) {
*cp++ = ' ';
while (*cp == '\r' || *cp == '\n') {
*cp++ = ' ';
}
} else {
cp++;
}
}
/*
* Now call the relevant script engine. Output is done directly
* by the ASP script procedure by calling websWrite()
*/
if (*nextp) {
result = NULL;
if (engine == EMF_SCRIPT_EJSCRIPT) {
rc = scriptEval(engine, nextp, &result, ejid);
} else {
rc = scriptEval(engine, nextp, &result, (int) wp);
}
if (rc < 0) {
/*
* On an error, discard all output accumulated so far
* and store the error in the result buffer. Be careful if the
* user has called websError() already.
*/
if (websValid(wp)) {
if (result) {
websWrite(wp, T("<h2><b>ASP Error: %s</b></h2>\n"),
result);
websWrite(wp, T("<pre>%s</pre>"), nextp);
bfree(B_L, result);
} else {
websWrite(wp, T("<h2><b>ASP Error</b></h2>\n%s\n"),
nextp);
}
websWrite(wp, T("</body></html>\n"));
rc = 0;
}
goto done;
}
}
} else {
websError(wp, 200, T("Unterminated script in %s: \n"), lpath);
rc = -1;
goto done;
}
}
/*
* Output any trailing HTML page text
*/
if (last && *last && rc == 0) {
websWriteBlock(wp, last, gstrlen(last));
}
rc = 0;
/*
* Common exit and cleanup
*/
done:
if (websValid(wp)) {
websPageClose(wp);
if (ejid >= 0) {
ejCloseEngine(ejid);
}
}
bfreeSafe(B_L, buf);
bfreeSafe(B_L, rbuf);
return rc;
}
/******************************************************************************/
/*
* Define an ASP Ejscript function. Bind an ASP name to a C procedure.
*/
int websAspDefine(char_t *name,
int (*fn)(int ejid, webs_t wp, int argc, char_t **argv))
{
return ejSetGlobalFunctionDirect(websAspFunctions, name,
(int (*)(int, void*, int, char_t**)) fn);
}
/******************************************************************************/
/*
* Asp write command. This implemements <% write("text"); %> command
*/
int websAspWrite(int ejid, webs_t wp, int argc, char_t **argv)
{
int i;
a_assert(websValid(wp));
for (i = 0; i < argc; ) {
a_assert(argv);
if (websWriteBlock(wp, argv[i], gstrlen(argv[i])) < 0) {
return -1;
}
if (++i < argc) {
if (websWriteBlock(wp, T(" "), 2) < 0) {
return -1;
}
}
}
return 0;
}
/******************************************************************************/
/*
* strtokcmp -- Find s2 in s1. We skip leading white space in s1.
* Return a pointer to the location in s1 after s2 ends.
*/
static char_t *strtokcmp(char_t *s1, char_t *s2)
{
int len;
s1 = skipWhite(s1);
len = gstrlen(s2);
for (len = gstrlen(s2); len > 0 && (tolower(*s1) == tolower(*s2)); len--) {
if (*s2 == '\0') {
return s1;
}
s1++;
s2++;
}
if (len == 0) {
return s1;
}
return NULL;
}
/******************************************************************************/
/*
* Skip white space
*/
static char_t *skipWhite(char_t *s)
{
a_assert(s);
if (s == NULL) {
return s;
}
while (*s && gisspace(*s)) {
s++;
}
return s;
}
/******************************************************************************/

View File

@@ -1,967 +0,0 @@
/*
* balloc.c -- Block allocation module
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* This module implements a very fast block allocation scheme suitable for
* ROMed environments. It maintains block class queues for rapid allocation
* and minimal fragmentation. This module does not coalesce blocks. The
* storage space may be populated statically or via the traditional malloc
* mechanisms. Large blocks greater than the maximum class size may be
* allocated from the O/S or run-time system via malloc. To permit the use
* of malloc, call bopen with flags set to B_USE_MALLOC (this is the default).
* It is recommended that bopen be called first thing in the application.
* If it is not, it will be called with default values on the first call to
* balloc(). Note that this code is not designed for multi-threading purposes
* and it depends on newly declared variables being initialized to zero.
*/
/********************************* Includes ***********************************/
#define IN_BALLOC
#ifdef UEMF
#include "uemf.h"
#else
#include "basic/basicInternal.h"
#endif
#include <stdarg.h>
#include <stdlib.h>
#ifndef NO_BALLOC
/********************************* Defines ************************************/
/*
* Define B_STATS if you wish to track memory block and stack usage
*/
#ifdef B_STATS
/*
* Optional statistics
*/
typedef struct {
long alloc; /* Block allocation calls */
long inuse; /* Blocks in use */
} bStatsType;
typedef struct {
char_t file[FNAMESIZE];
long allocated; /* Bytes currently allocated */
long count; /* Current block count */
long times; /* Count of alloc attempts */
long largest; /* largest allocated here */
int q;
} bStatsFileType;
/*
* This one is very expensive but great stats
*/
typedef struct {
void *ptr; /* Pointer to memory */
bStatsFileType *who; /* Who allocated the memory */
} bStatsBlkType;
static bStatsType bStats[B_MAX_CLASS]; /* Per class stats */
static bStatsFileType bStatsFiles[B_MAX_FILES];/* Per file stats */
static bStatsBlkType bStatsBlks[B_MAX_BLOCKS];/* Per block stats */
static int bStatsBlksMax = 0; /* Max block entry */
static int bStatsFilesMax = 0; /* Max file entry */
static int bStatsMemInUse = 0; /* Memory currently in use */
static int bStatsBallocInUse = 0; /* Memory currently balloced */
static int bStatsMemMax = 0; /* Max memory ever used */
static int bStatsBallocMax = 0; /* Max memory ever balloced */
static void *bStackMin = (void*) -1;/* Miniumum stack position */
static void *bStackStart; /* Starting stack position */
static int bStatsMemMalloc = 0; /* Malloced memory */
#endif /* B_STATS */
/*
* ROUNDUP4(size) returns the next higher integer value of size that is
* divisible by 4, or the value of size if size is divisible by 4.
* ROUNDUP4() is used in aligning memory allocations on 4-byte boundaries.
*
* Note: ROUNDUP4() is only required on some operating systems (IRIX).
*/
#define ROUNDUP4(size) ((size) % 4) ? (size) + (4 - ((size) % 4)) : (size)
/********************************** Locals ************************************/
/*
* bQhead blocks are created as the original memory allocation is freed up.
* See bfree.
*/
static bType *bQhead[B_MAX_CLASS]; /* Per class block q head */
static char *bFreeBuf; /* Pointer to free memory */
static char *bFreeNext; /* Pointer to next free mem */
static int bFreeSize; /* Size of free memory */
static int bFreeLeft; /* Size of free left for use */
static int bFlags = B_USE_MALLOC; /* Default to auto-malloc */
static int bopenCount = 0; /* Num tasks using balloc */
/*************************** Forward Declarations *****************************/
#ifdef B_STATS
static void bStatsAlloc(B_ARGS_DEC, void *ptr, int q, int size);
static void bStatsFree(B_ARGS_DEC, void *ptr, int q, int size);
static void bstatsWrite(int handle, char_t *fmt, ...);
static int bStatsFileSort(const void *cp1, const void *cp2);
#endif /* B_STATS */
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
static void bFillBlock(void *buf, int bufsize);
#endif
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
static void verifyUsedBlock(bType *bp, int q);
static void verifyFreeBlock(bType *bp, int q);
void verifyBallocSpace();
#endif
static int ballocGetSize(int size, int *q);
/********************************** Code **************************************/
/*
* Initialize the balloc module. bopen should be called the very first thing
* after the application starts and bclose should be called the last thing
* before exiting. If bopen is not called, it will be called on the first
* allocation with default values. "buf" points to memory to use of size
* "bufsize". If buf is NULL, memory is allocated using malloc. flags may
* be set to B_USE_MALLOC if using malloc is okay. This routine will allocate
* an initial buffer of size bufsize for use by the application.
*/
int bopen(void *buf, int bufsize, int flags)
{
bFlags = flags;
#ifdef BASTARD_TESTING
srand(time(0L));
#endif /* BASTARD_TESTING */
/*
* If bopen already called by a shared process, just increment the count
* and return;
*/
if (++bopenCount > 1) {
return 0;
}
if (buf == NULL) {
if (bufsize == 0) {
bufsize = B_DEFAULT_MEM;
}
#ifdef IRIX
bufsize = ROUNDUP4(bufsize);
#endif
if ((buf = malloc(bufsize)) == NULL) {
return -1;
}
#ifdef B_STATS
bStatsMemMalloc += bufsize;
#endif
} else {
bFlags |= B_USER_BUF;
}
bFreeSize = bFreeLeft = bufsize;
bFreeBuf = bFreeNext = buf;
memset(bQhead, 0, sizeof(bQhead));
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
bFillBlock(buf, bufsize);
#endif
#ifdef B_STATS
bStackStart = &buf;
#endif
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyFreeBlock(buf, bufsize);
#endif
return 0;
}
/******************************************************************************/
/*
* Close down the balloc module and free all malloced memory.
*/
void bclose()
{
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyBallocSpace();
#endif
if (--bopenCount <= 0 && !(bFlags & B_USER_BUF)) {
free(bFreeBuf);
bopenCount = 0;
}
}
/******************************************************************************/
/*
* Allocate a block of the requested size. First check the block
* queues for a suitable one.
*/
void *balloc(B_ARGS_DEC, int size)
{
bType *bp;
int q, memSize;
/*
* Call bopen with default values if the application has not yet done so
*/
if (bFreeBuf == NULL) {
if (bopen(NULL, B_DEFAULT_MEM, 0) < 0) {
return NULL;
}
}
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyBallocSpace();
#endif
if (size < 0) {
return NULL;
}
#ifdef BASTARD_TESTING
if (rand() == 0x7fff) {
return NULL;
}
#endif /* BASTARD_TESTING */
memSize = ballocGetSize(size, &q);
if (q >= B_MAX_CLASS) {
/*
* Size if bigger than the maximum class. Malloc if use has been okayed
*/
if (bFlags & B_USE_MALLOC) {
#ifdef B_STATS
bstats(0, NULL);
#endif
#ifdef IRIX
memSize = ROUNDUP4(memSize);
#endif
bp = (bType*) malloc(memSize);
if (bp == NULL) {
traceRaw(T("B: malloc failed\n"));
return NULL;
}
#ifdef B_STATS
bStatsMemMalloc += memSize;
#endif
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
bFillBlock(bp, memSize);
#endif
} else {
traceRaw(T("B: malloc failed\n"));
return NULL;
}
/*
* the u.size is the actual size allocated for data
*/
bp->u.size = memSize - sizeof(bType);
bp->flags = B_MALLOCED;
} else if ((bp = bQhead[q]) != NULL) {
/*
* Take first block off the relevant q if non-empty
*/
bQhead[q] = bp->u.next;
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyFreeBlock(bp, q);
#endif
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
bFillBlock(bp, memSize);
#endif
bp->u.size = memSize - sizeof(bType);
bp->flags = 0;
} else {
if (bFreeLeft > memSize) {
/*
* The q was empty, and the free list has spare memory so
* create a new block out of the primary free block
*/
bp = (bType*) bFreeNext;
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyFreeBlock(bp, q);
#endif
bFreeNext += memSize;
bFreeLeft -= memSize;
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
bFillBlock(bp, memSize);
#endif
bp->u.size = memSize - sizeof(bType);
bp->flags = 0;
} else if (bFlags & B_USE_MALLOC) {
#ifdef B_STATS
static int once = 0;
if (once++ == 0) {
bstats(0, NULL);
}
#endif
/*
* Nothing left on the primary free list, so malloc a new block
*/
#ifdef IRIX
memSize = ROUNDUP4(memSize);
#endif
if ((bp = (bType*) malloc(memSize)) == NULL) {
traceRaw(T("B: malloc failed\n"));
return NULL;
}
#ifdef B_STATS
bStatsMemMalloc += memSize;
#endif
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
bFillBlock(bp, memSize);
#endif
bp->u.size = memSize - sizeof(bType);
bp->flags = B_MALLOCED;
} else {
traceRaw(T("B: malloc failed\n"));
return NULL;
}
}
#ifdef B_STATS
bStatsAlloc(B_ARGS, bp, q, memSize);
#endif
bp->flags |= B_INTEGRITY;
/*
* The following is a good place to put a breakpoint when trying to reduce
* determine and reduce maximum memory use.
*/
#if 0
#ifdef B_STATS
if (bStatsBallocInUse == bStatsBallocMax) {
bstats(0, NULL);
}
#endif
#endif
return (void*) ((char*) bp + sizeof(bType));
}
/******************************************************************************/
/*
* Free a block back to the relevant free q. We don't free back to the O/S
* or run time system unless the block is greater than the maximum class size.
* We also do not coalesce blocks.
*/
void bfree(B_ARGS_DEC, void *mp)
{
bType *bp;
int q, memSize;
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyBallocSpace();
#endif
bp = (bType*) ((char*) mp - sizeof(bType));
a_assert((bp->flags & B_INTEGRITY_MASK) == B_INTEGRITY);
if ((bp->flags & B_INTEGRITY_MASK) != B_INTEGRITY) {
return;
}
memSize = ballocGetSize(bp->u.size, &q);
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyUsedBlock(bp,q);
#endif
#ifdef B_STATS
bStatsFree(B_ARGS, bp, q, bp->u.size+sizeof(bType));
#endif
if (bp->flags & B_MALLOCED) {
free(bp);
return;
}
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
bFillBlock(bp, memSize);
#endif
/*
* Simply link onto the head of the relevant q
*/
bp->u.next = bQhead[q];
bQhead[q] = bp;
bp->flags = B_FILL_WORD;
}
/******************************************************************************/
/*
* Safe free
*/
void bfreeSafe(B_ARGS_DEC, void *mp)
{
if (mp) {
bfree(B_ARGS, mp);
}
}
/******************************************************************************/
#ifdef UNICODE
/*
* Duplicate a string, allow NULL pointers and then dup an empty string.
*/
char *bstrdupA(B_ARGS_DEC, char *s)
{
char *cp;
int len;
if (s == NULL) {
s = "";
}
len = strlen(s) + 1;
if (cp = balloc(B_ARGS, len)) {
strcpy(cp, s);
}
return cp;
}
#endif /* UNICODE */
/******************************************************************************/
/*
* Duplicate an ascii string, allow NULL pointers and then dup an empty string.
* If UNICODE, bstrdup above works with wide chars, so we need this routine
* for ascii strings.
*/
char_t *bstrdup(B_ARGS_DEC, char_t *s)
{
char_t *cp;
int len;
if (s == NULL) {
s = T("");
}
len = gstrlen(s) + 1;
if ((cp = balloc(B_ARGS, len * sizeof(char_t))) != NULL) {
gstrcpy(cp, s);
}
return cp;
}
/******************************************************************************/
/*
* Reallocate a block. Allow NULL pointers and just do a malloc.
* Note: if the realloc fails, we return NULL and the previous buffer is
* preserved.
*/
void *brealloc(B_ARGS_DEC, void *mp, int newsize)
{
bType *bp;
void *newbuf;
if (mp == NULL) {
return balloc(B_ARGS, newsize);
}
bp = (bType*) ((char*) mp - sizeof(bType));
a_assert((bp->flags & B_INTEGRITY_MASK) == B_INTEGRITY);
/*
* If the allocated memory already has enough room just return the previously
* allocated address.
*/
if (bp->u.size >= newsize) {
return mp;
}
if ((newbuf = balloc(B_ARGS, newsize)) != NULL) {
memcpy(newbuf, mp, bp->u.size);
bfree(B_ARGS, mp);
}
return newbuf;
}
/******************************************************************************/
/*
* Find the size of the block to be balloc'ed. It takes in a size, finds the
* smallest binary block it fits into, adds an overhead amount and returns.
* q is the binary size used to keep track of block sizes in use. Called
* from both balloc and bfree.
*/
static int ballocGetSize(int size, int *q)
{
int mask;
mask = (size == 0) ? 0 : (size-1) >> B_SHIFT;
for (*q = 0; mask; mask >>= 1) {
*q = *q + 1;
}
return ((1 << (B_SHIFT + *q)) + sizeof(bType));
}
/******************************************************************************/
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
/*
* Fill the block (useful during development to catch zero fill assumptions)
*/
static void bFillBlock(void *buf, int bufsize)
{
memset(buf, B_FILL_CHAR, bufsize);
}
#endif
/******************************************************************************/
#ifdef B_STATS
/*
* Statistics. Do output via calling the writefn callback function with
* "handle" as the output file handle.
*/
void bstats(int handle, void (*writefn)(int handle, char_t *fmt, ...))
{
bStatsFileType *fp, *files;
bStatsBlkType *blkp;
bType *bp;
char_t *cp;
int q, count, mem, total, len;
static int recurseProtect = 0;
if (recurseProtect++ > 0) {
recurseProtect--;
return;
}
if (writefn == NULL) {
writefn = bstatsWrite;
}
/*
* Print stats for each memory block
*/
(*writefn)(handle, T("\nMemory Stats\n"));
/*
* The following tabular format is now used for the output.
* Q Size Free Bytes Inuse Bytes Allocs
* dd ddddd ddd ddddd dddd ddddd dddd
*/
(*writefn)(handle, " Q Size Free Bytes Inuse Bytes Allocs\n");
total = 0;
for (q = 0; q < B_MAX_CLASS; q++) {
count = 0;
for (bp = bQhead[q]; bp; bp = bp->u.next) {
count++;
}
mem = count * (1 << (q + B_SHIFT));
total += mem;
(*writefn)(handle,
T("%2d %5d %4d %6d %4d %5d %4d\n"),
q, 1 << (q + B_SHIFT), count, mem, bStats[q].inuse,
bStats[q].inuse * (1 << (q + B_SHIFT)), bStats[q].alloc);
}
(*writefn)(handle, T("\n"));
/*
* Print summary stats
*
* bFreeSize Initial memory reserved with bopen call
* bStatsMemMalloc memory from calls to system MALLOC
* bStatsMemMax
* bStatsBallocMax largest amount of memory from balloc calls
* bStatsMemInUse
* bStatsBallocInUse present balloced memory being used
* bStatsBlksMax);
* bStackStart
* bStackMin);
* total);
* bFreeLeft);
*
*/
(*writefn)(handle, T("Initial free list size %7d\n"), bFreeSize);
(*writefn)(handle, T("Max memory malloced %7d\n"), bStatsMemMalloc);
(*writefn)(handle, T("Max memory ever used %7d\n"), bStatsMemMax);
(*writefn)(handle, T("Max memory ever balloced %7d\n"), bStatsBallocMax);
(*writefn)(handle, T("Memory currently in use %7d\n"), bStatsMemInUse);
(*writefn)(handle, T("Memory currently balloced %7d\n"), bStatsBallocInUse);
(*writefn)(handle, T("Max blocks allocated %7d\n"), bStatsBlksMax);
(*writefn)(handle, T("Maximum stack used %7d\n"),
(int) bStackStart - (int) bStackMin);
(*writefn)(handle, T("Free memory on all queues %7d\n"), total);
(*writefn)(handle, T("Free list buffer left %7d\n"), bFreeLeft);
(*writefn)(handle, T("Total free memory %7d\n"), bFreeLeft + total);
/*
* Print per file allocation stats. Sort the copied table.
*/
len = sizeof(bStatsFileType) * B_MAX_FILES;
files = malloc(len);
if (files == NULL) {
(*writefn)(handle, T("Can't allocate stats memory\n"));
recurseProtect--;
return;
}
memcpy(files, bStatsFiles, len);
qsort(files, bStatsFilesMax, sizeof(bStatsFileType), bStatsFileSort);
(*writefn)(handle, T("\nMemory Currently Allocated\n"));
total = 0;
(*writefn)(handle,
T(" bytes, blocks in use, total times,")
T("largest, q\n"));
for (fp = files; fp < &files[bStatsFilesMax]; fp++) {
if (fp->file[0]) {
(*writefn)(handle, T("%18s, %7d, %5d, %6d, %7d,%4d\n"),
fp->file, fp->allocated, fp->count, fp->times, fp->largest,
fp->q);
total += fp->allocated;
}
}
(*writefn)(handle, T("\nTotal allocated %7d\n\n"), total);
/*
* Dump the actual strings
*/
(*writefn)(handle, T("\nStrings\n"));
for (blkp = &bStatsBlks[bStatsBlksMax - 1]; blkp >= bStatsBlks; blkp--) {
if (blkp->ptr) {
cp = (char_t*) ((char*) blkp->ptr + sizeof(bType));
fp = blkp->who;
if (gisalnum(*cp)) {
(*writefn)(handle, T("%-50s allocated by %s\n"), cp,
fp->file);
}
}
}
free(files);
recurseProtect--;
}
/******************************************************************************/
/*
* File sort function. Used to sort per file stats
*/
static int bStatsFileSort(const void *cp1, const void *cp2)
{
bStatsFileType *s1, *s2;
s1 = (bStatsFileType*) cp1;
s2 = (bStatsFileType*) cp2;
if (s1->allocated < s2->allocated)
return -1;
else if (s1->allocated == s2->allocated)
return 0;
return 1;
}
/******************************************************************************/
/*
* Accumulate allocation statistics
*/
static void bStatsAlloc(B_ARGS_DEC, void *ptr, int q, int size)
{
int memSize;
bStatsFileType *fp;
bStatsBlkType *bp;
char_t name[FNAMESIZE + 10];
gsprintf(name, T("%s:%d"), B_ARGS);
bStats[q].alloc++;
bStats[q].inuse++;
bStatsMemInUse += size;
if (bStatsMemInUse > bStatsMemMax) {
bStatsMemMax = bStatsMemInUse;
}
memSize = (1 << (B_SHIFT + q)) + sizeof(bType);
bStatsBallocInUse += memSize;
if (bStatsBallocInUse > bStatsBallocMax) {
bStatsBallocMax = bStatsBallocInUse;
}
/*
* Track maximum stack usage. Assumes a stack growth down. Approximate as
* we only measure this on block allocation.
*/
if ((void*) &file < bStackMin) {
bStackMin = (void*) &file;
}
/*
* Find the file and adjust the stats for this file
*/
for (fp = bStatsFiles; fp < &bStatsFiles[bStatsFilesMax]; fp++) {
if (fp->file[0] == file[0] && gstrcmp(fp->file, name) == 0) {
fp->allocated += size;
fp->count++;
fp->times++;
if (fp->largest < size) {
fp->largest = size;
fp->q = q;
}
break;
}
}
/*
* New entry: find the first free slot and create a new entry
*/
if (fp >= &bStatsFiles[bStatsFilesMax]) {
for (fp = bStatsFiles; fp < &bStatsFiles[B_MAX_FILES]; fp++) {
if (fp->file[0] == '\0') {
gstrncpy(fp->file, name, TSZ(fp->file));
fp->allocated += size;
fp->count++;
fp->times++;
fp->largest = size;
fp->q = q;
if ((fp - bStatsFiles) >= bStatsFilesMax) {
bStatsFilesMax = (fp - bStatsFiles) + 1;
}
break;
}
}
}
/*
* Update the per block stats. Allocate a new slot.
*/
for (bp = bStatsBlks; bp < &bStatsBlks[B_MAX_BLOCKS]; bp++) {
if (bp->ptr == NULL) {
bp->ptr = ptr;
bp->who = fp;
if ((bp - bStatsBlks) >= bStatsBlksMax) {
bStatsBlksMax = (bp - bStatsBlks) + 1;
}
break;
}
}
}
/******************************************************************************/
/*
* Free statistics
*/
static void bStatsFree(B_ARGS_DEC, void *ptr, int q, int size)
{
int memSize;
bStatsFileType *fp;
bStatsBlkType *bp;
memSize = (1 << (B_SHIFT + q)) + sizeof(bType);
bStatsMemInUse -= size;
bStatsBallocInUse -= memSize;
bStats[q].inuse--;
/*
* Update the per block stats. Try from the end first
*/
for (bp = &bStatsBlks[bStatsBlksMax - 1]; bp >= bStatsBlks; bp--) {
if (bp->ptr == ptr) {
bp->ptr = NULL;
fp = bp->who;
bp->who = NULL;
fp->allocated -= size;
fp->count--;
return;
}
}
}
/******************************************************************************/
/*
* Default output function. Just send to trace channel.
*/
#undef sprintf
static void bstatsWrite(int handle, char_t *fmt, ...)
{
va_list args;
char_t buf[BUF_MAX];
va_start(args, fmt);
vsprintf(buf, fmt, args);
va_end(args);
traceRaw(buf);
}
#else /* not B_STATS */
/******************************************************************************/
/*
* Dummy bstats for external calls that aren't protected by #if B_STATS.
*/
void bstats(int handle, void (*writefn)(int handle, char_t *fmt, ...))
{
}
#endif /* B_STATS */
/******************************************************************************/
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
/*
* The following routines verify the integrity of the balloc memory space.
* These functions use the B_FILL feature. Corruption is defined
* as bad integrity flags in allocated blocks or data other than B_FILL_CHAR
* being found anywhere in the space which is unallocated and that is not a
* next pointer in the free queues. a_assert is called if any corruption is
* found. CAUTION: These functions add severe processing overhead and should
* only be used when searching for a tough corruption problem.
*/
/******************************************************************************/
/*
* verifyUsedBlock verifies that a block which was previously allocated is
* still uncorrupted.
*/
static void verifyUsedBlock(bType *bp, int q)
{
int memSize, size;
char *p;
memSize = (1 << (B_SHIFT + q)) + sizeof(bType);
a_assert((bp->flags & ~B_MALLOCED) == B_INTEGRITY);
size = bp->u.size;
for (p = ((char *)bp)+sizeof(bType)+size; p < ((char*)bp)+memSize; p++) {
a_assert(*p == B_FILL_CHAR);
}
}
/******************************************************************************/
/*
* verifyFreeBlock verifies that a previously free'd block in one of the queues
* is still uncorrupted.
*/
static void verifyFreeBlock(bType *bp, int q)
{
int memSize;
char *p;
memSize = (1 << (B_SHIFT + q)) + sizeof(bType);
for (p = ((char *)bp)+sizeof(void*); p < ((char*)bp)+memSize; p++) {
a_assert(*p == B_FILL_CHAR);
}
bp = (bType *)p;
a_assert((bp->flags & ~B_MALLOCED) == B_INTEGRITY ||
bp->flags == B_FILL_WORD);
}
/******************************************************************************/
/*
* verifyBallocSpace reads through the entire balloc memory space and
* verifies that all allocated blocks are uncorrupted and that, with the
* exception of free list next pointers, all other unallocated space is
* filled with B_FILL_CHAR.
*/
void verifyBallocSpace()
{
int q;
char *p;
bType *bp;
/*
* First verify all the free blocks.
*/
for (q = 0; q < B_MAX_CLASS; q++) {
for (bp = bQhead[q]; bp != NULL; bp = bp->u.next) {
verifyFreeBlock(bp, q);
}
}
/*
* Now verify other space
*/
p = bFreeBuf;
while (p < (bFreeBuf + bFreeSize)) {
bp = (bType *)p;
if (bp->u.size > 0xFFFFF) {
p += sizeof(bp->u);
while (p < (bFreeBuf + bFreeSize) && *p == B_FILL_CHAR) {
p++;
}
} else {
a_assert(((bp->flags & ~B_MALLOCED) == B_INTEGRITY) ||
bp->flags == B_FILL_WORD);
p += (sizeof(bType) + bp->u.size);
while (p < (bFreeBuf + bFreeSize) && *p == B_FILL_CHAR) {
p++;
}
}
}
}
#endif /* B_VERIFY_CAUSES_SEVERE_OVERHEAD */
/******************************************************************************/
#else /* NO_BALLOC */
int bopen(void *buf, int bufsize, int flags)
{
return 0;
}
/******************************************************************************/
void bclose()
{
}
/******************************************************************************/
void bstats(int handle, void (*writefn)(int handle, char_t *fmt, ...))
{
}
/******************************************************************************/
char_t *bstrdupNoBalloc(char_t *s)
{
#ifdef UNICODE
if (s) {
return wcsdup(s);
} else {
return wcsdup(T(""));
}
#else
return bstrdupANoBalloc(s);
#endif
}
/******************************************************************************/
char *bstrdupANoBalloc(char *s)
{
char* buf;
if (s == NULL) {
s = "";
}
buf = malloc(strlen(s)+1);
strcpy(buf, s);
return buf;
}
#endif /* NO_BALLOC */
/******************************************************************************/

View File

@@ -1,331 +0,0 @@
/*
* cgi.c -- CGI processing (for the GoAhead Web server
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/********************************** Description *******************************/
/*
* This module implements the /cgi-bin handler. CGI processing differs from
* goforms processing in that each CGI request is executed as a separate
* process, rather than within the webserver process. For each CGI request the
* environment of the new process must be set to include all the CGI variables
* and its standard input and output must be directed to the socket. This
* is done using temporary files.
*/
/*********************************** Includes *********************************/
#include "wsIntrn.h"
#ifdef UEMF
#include "uemf.h"
#else
#include "basic/basicInternal.h"
#endif
/************************************ Locals **********************************/
typedef struct { /* Struct for CGI tasks which have completed */
webs_t wp; /* pointer to session websRec */
char_t *stdIn; /* file desc. for task's temp input fd */
char_t *stdOut; /* file desc. for task's temp output fd */
char_t *cgiPath; /* path to executable process file */
char_t **argp; /* pointer to buf containing argv tokens */
char_t **envp; /* pointer to array of environment strings */
int handle; /* process handle of the task */
long fplacemark; /* seek location for CGI output file */
} cgiRec;
static cgiRec **cgiList; /* hAlloc chain list of wp's to be closed */
static int cgiMax; /* Size of hAlloc list */
/************************************* Code ***********************************/
/*
* Process a form request. Returns 1 always to indicate it handled the URL
*/
int websCgiHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg,
char_t *url, char_t *path, char_t* query)
{
cgiRec *cgip;
sym_t *s;
char_t cgiBuf[FNAMESIZE], *stdIn, *stdOut, cwd[FNAMESIZE];
char_t *cp, *cgiName, *cgiPath, **argp, **envp, **ep;
int n, envpsize, argpsize, pHandle, cid;
a_assert(websValid(wp));
a_assert(url && *url);
a_assert(path && *path == '/');
websStats.cgiHits++;
/*
* Extract the form name and then build the full path name. The form
* name will follow the first '/' in path.
*/
gstrncpy(cgiBuf, path, TSZ(cgiBuf));
if ((cgiName = gstrchr(&cgiBuf[1], '/')) == NULL) {
websError(wp, 200, T("Missing CGI name"));
return 1;
}
cgiName++;
if ((cp = gstrchr(cgiName, '/')) != NULL) {
*cp = '\0';
}
fmtAlloc(&cgiPath, FNAMESIZE, T("%s/%s/%s"), websGetDefaultDir(),
CGI_BIN, cgiName);
#ifndef VXWORKS
/*
* See if the file exists and is executable. If not error out.
* Don't do this step for VxWorks, since the module may already
* be part of the OS image, rather than in the file system.
*/
{
gstat_t sbuf;
if (gstat(cgiPath, &sbuf) != 0 || (sbuf.st_mode & S_IFREG) == 0) {
websError(wp, 200, T("CGI process file does not exist"));
bfree(B_L, cgiPath);
return 1;
}
#if (defined (WIN) || defined (CE))
if (gstrstr(cgiPath, T(".exe")) == NULL &&
gstrstr(cgiPath, T(".bat")) == NULL) {
#elif (defined (NW))
if (gstrstr(cgiPath, T(".nlm")) == NULL) {
#else
if (gaccess(cgiPath, X_OK) != 0) {
#endif /* WIN || CE */
websError(wp, 200, T("CGI process file is not executable"));
bfree(B_L, cgiPath);
return 1;
}
}
#endif /* ! VXWORKS */
/*
* Get the CWD for resetting after launching the child process CGI
*/
ggetcwd(cwd, FNAMESIZE);
/*
* Retrieve the directory of the child process CGI
*/
if ((cp = gstrrchr(cgiPath, '/')) != NULL) {
*cp = '\0';
gchdir(cgiPath);
*cp = '/';
}
/*
* Build command line arguments. Only used if there is no non-encoded
* = character. This is indicative of a ISINDEX query. POST separators
* are & and others are +. argp will point to a balloc'd array of
* pointers. Each pointer will point to substring within the
* query string. This array of string pointers is how the spawn or
* exec routines expect command line arguments to be passed. Since
* we don't know ahead of time how many individual items there are in
* the query string, the for loop includes logic to grow the array
* size via brealloc.
*/
argpsize = 10;
argp = balloc(B_L, argpsize * sizeof(char_t *));
*argp = cgiPath;
n = 1;
if (gstrchr(query, '=') == NULL) {
websDecodeUrl(query, query, gstrlen(query));
for (cp = gstrtok(query, T(" ")); cp != NULL; ) {
*(argp+n) = cp;
n++;
if (n >= argpsize) {
argpsize *= 2;
argp = brealloc(B_L, argp, argpsize * sizeof(char_t *));
}
cp = gstrtok(NULL, T(" "));
}
}
*(argp+n) = NULL;
/*
* Add all CGI variables to the environment strings to be passed
* to the spawned CGI process. This includes a few we don't
* already have in the symbol table, plus all those that are in
* the cgiVars symbol table. envp will point to a balloc'd array of
* pointers. Each pointer will point to a balloc'd string containing
* the keyword value pair in the form keyword=value. Since we don't
* know ahead of time how many environment strings there will be the
* for loop includes logic to grow the array size via brealloc.
*/
envpsize = WEBS_SYM_INIT;
envp = balloc(B_L, envpsize * sizeof(char_t *));
n = 0;
fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"),T("PATH_TRANSLATED"), cgiPath);
n++;
fmtAlloc(envp+n, FNAMESIZE, T("%s=%s/%s"),T("SCRIPT_NAME"),
CGI_BIN, cgiName);
n++;
fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"),T("REMOTE_USER"), wp->userName);
n++;
fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"),T("AUTH_TYPE"), wp->authType);
n++;
for (s = symFirst(wp->cgiVars); s != NULL; s = symNext(wp->cgiVars)) {
if (s->content.valid && s->content.type == string &&
gstrcmp(s->name.value.string, T("REMOTE_HOST")) != 0 &&
gstrcmp(s->name.value.string, T("HTTP_AUTHORIZATION")) != 0) {
fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"), s->name.value.string,
s->content.value.string);
n++;
if (n >= envpsize) {
envpsize *= 2;
envp = brealloc(B_L, envp, envpsize * sizeof(char_t *));
}
}
}
*(envp+n) = NULL;
/*
* Create temporary file name(s) for the child's stdin and stdout.
* For POST data the stdin temp file (and name) should already exist.
*/
if (wp->cgiStdin == NULL) {
wp->cgiStdin = websGetCgiCommName();
}
stdIn = wp->cgiStdin;
stdOut = websGetCgiCommName();
/*
* Now launch the process. If not successful, do the cleanup of resources.
* If successful, the cleanup will be done after the process completes.
*/
if ((pHandle = websLaunchCgiProc(cgiPath, argp, envp, stdIn, stdOut))
== -1) {
websError(wp, 200, T("failed to spawn CGI task"));
for (ep = envp; *ep != NULL; ep++) {
bfreeSafe(B_L, *ep);
}
bfreeSafe(B_L, cgiPath);
bfreeSafe(B_L, argp);
bfreeSafe(B_L, envp);
bfreeSafe(B_L, stdOut);
} else {
/*
* If the spawn was successful, put this wp on a queue to be
* checked for completion.
*/
cid = hAllocEntry((void***) &cgiList, &cgiMax, sizeof(cgiRec));
cgip = cgiList[cid];
cgip->handle = pHandle;
cgip->stdIn = stdIn;
cgip->stdOut = stdOut;
cgip->cgiPath = cgiPath;
cgip->argp = argp;
cgip->envp = envp;
cgip->wp = wp;
cgip->fplacemark = 0;
websTimeoutCancel(wp);
}
/*
* Restore the current working directory after spawning child CGI
*/
gchdir(cwd);
return 1;
}
/******************************************************************************/
/*
* Any entry in the cgiList need to be checked to see if it has
*/
void websCgiGatherOutput (cgiRec *cgip)
{
gstat_t sbuf;
char_t cgiBuf[FNAMESIZE];
if ((gstat(cgip->stdOut, &sbuf) == 0) &&
(sbuf.st_size > cgip->fplacemark)) {
int fdout;
fdout = gopen(cgip->stdOut, O_RDONLY | O_BINARY, 0444 );
/*
* Check to see if any data is available in the
* output file and send its contents to the socket.
*/
if (fdout >= 0) {
webs_t wp = cgip->wp;
int nRead;
/*
* Write the HTTP header on our first pass
*/
if (cgip->fplacemark == 0) {
websWrite(wp, T("HTTP/1.0 200 OK\r\n"));
}
glseek(fdout, cgip->fplacemark, SEEK_SET);
while ((nRead = gread(fdout, cgiBuf, FNAMESIZE)) > 0) {
websWriteBlock(wp, cgiBuf, nRead);
cgip->fplacemark += nRead;
}
gclose(fdout);
}
}
}
/******************************************************************************/
/*
* Any entry in the cgiList need to be checked to see if it has
* completed, and if so, process its output and clean up.
*/
void websCgiCleanup()
{
cgiRec *cgip;
webs_t wp;
char_t **ep;
int cid, nTries;
for (cid = 0; cid < cgiMax; cid++) {
if ((cgip = cgiList[cid]) != NULL) {
wp = cgip->wp;
websCgiGatherOutput (cgip);
if (websCheckCgiProc(cgip->handle) == 0) {
/*
* We get here if the CGI process has terminated. Clean up.
*/
nTries = 0;
/*
* Make sure we didn't miss something during a task switch.
* Maximum wait is 100 times 10 msecs (1 second).
*/
while ((cgip->fplacemark == 0) && (nTries < 100)) {
websCgiGatherOutput(cgip);
/*
* There are some cases when we detect app exit
* before the file is ready.
*/
if (cgip->fplacemark == 0) {
#ifdef WIN
Sleep(10);
#endif /* WIN*/
}
nTries++;
}
if (cgip->fplacemark == 0) {
websError(wp, 200, T("CGI generated no output"));
} else {
websDone(wp, 200);
}
/*
* Remove the temporary re-direction files
*/
gunlink(cgip->stdIn);
gunlink(cgip->stdOut);
/*
* Free all the memory buffers pointed to by cgip.
* The stdin file name (wp->cgiStdin) gets freed as
* part of websFree().
*/
cgiMax = hFree((void***) &cgiList, cid);
for (ep = cgip->envp; ep != NULL && *ep != NULL; ep++) {
bfreeSafe(B_L, *ep);
}
bfreeSafe(B_L, cgip->cgiPath);
bfreeSafe(B_L, cgip->argp);
bfreeSafe(B_L, cgip->envp);
bfreeSafe(B_L, cgip->stdOut);
bfreeSafe(B_L, cgip);
}
}
}
}
/******************************************************************************/

View File

@@ -1,431 +0,0 @@
/*
* default.c -- Default URL handler. Includes support for ASP.
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* This module provides default URL handling and Active Server Page support.
*
* In many cases we don't check the return code of calls to websWrite as
* it is easier, smaller and non-fatal to continue even when the requesting
* browser has gone away.
*/
/********************************* Includes ***********************************/
#include "wsIntrn.h"
/*********************************** Locals ***********************************/
static char_t *websDefaultPage; /* Default page name */
static char_t *websDefaultDir; /* Default Web page directory */
/**************************** Forward Declarations ****************************/
static void websDefaultWriteEvent(webs_t wp);
/*********************************** Code *************************************/
/*
* Process a default URL request. This will validate the URL and handle "../"
* and will provide support for Active Server Pages. As the handler is the
* last handler to run, it always indicates that it has handled the URL
* by returning 1.
*/
int websDefaultHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg,
char_t *url, char_t *path, char_t *query)
{
websStatType sbuf;
char_t *lpath, *tmp, *date;
int bytes, flags, nchars;
a_assert(websValid(wp));
a_assert(url && *url);
a_assert(path);
a_assert(query);
/*
* Validate the URL and ensure that ".."s don't give access to unwanted files
*/
flags = websGetRequestFlags(wp);
if (websValidateUrl(wp, path) < 0) {
websError(wp, 500, T("Invalid URL %s"), url);
return 1;
}
lpath = websGetRequestLpath(wp);
nchars = gstrlen(lpath) - 1;
if (lpath[nchars] == '/' || lpath[nchars] == '\\') {
lpath[nchars] = '\0';
}
/*
* If the file is a directory, redirect using the nominated default page
*/
if (websPageIsDirectory(lpath)) {
nchars = gstrlen(path);
if (path[nchars-1] == '/' || path[nchars-1] == '\\') {
path[--nchars] = '\0';
}
nchars += gstrlen(websDefaultPage) + 2;
fmtAlloc(&tmp, nchars, T("%s/%s"), path, websDefaultPage);
websRedirect(wp, tmp);
bfreeSafe(B_L, tmp);
return 1;
}
/*
* Open the document. Stat for later use.
*/
if (websPageOpen(wp, lpath, path, SOCKET_RDONLY | SOCKET_BINARY,
0666) < 0) {
websError(wp, 400, T("Cannot open URL <b>%s</b>"), url);
return 1;
}
if (websPageStat(wp, lpath, path, &sbuf) < 0) {
websError(wp, 400, T("Cannot stat page for URL <b>%s</b>"), url);
return 1;
}
/*
* If the page has not been modified since the user last received it and it
* is not dynamically generated each time (ASP), then optimize request by
* sending a 304 Use local copy response
*/
websStats.localHits++;
#ifdef WEBS_IF_MODIFIED_SUPPORT
if (flags & WEBS_IF_MODIFIED && !(flags & WEBS_ASP)) {
if (sbuf.mtime <= wp->since) {
websWrite(wp, T("HTTP/1.0 304 Use local copy\r\n"));
/*
* by license terms the following line of code must
* not be modified.
*/
websWrite(wp, T("Server: %s\r\n"), WEBS_NAME);
if (flags & WEBS_KEEP_ALIVE) {
websWrite(wp, T("Connection: keep-alive\r\n"));
}
websWrite(wp, T("\r\n"));
websSetRequestFlags(wp, flags |= WEBS_HEADER_DONE);
websDone(wp, 304);
return 1;
}
}
#endif
/*
* Output the normal HTTP response header
*/
if ((date = websGetDateString(NULL)) != NULL) {
websWrite(wp, T("HTTP/1.0 200 OK\r\nDate: %s\r\n"), date);
/*
* By license terms the following line of code must not be modified.
*/
websWrite(wp, T("Server: %s\r\n"), WEBS_NAME);
bfree(B_L, date);
}
flags |= WEBS_HEADER_DONE;
/*
* If this is an ASP request, ensure the remote browser doesn't cache it.
* Send back both HTTP/1.0 and HTTP/1.1 cache control directives
*/
if (flags & WEBS_ASP) {
bytes = 0;
websWrite(wp, T("Pragma: no-cache\r\nCache-Control: no-cache\r\n"));
} else {
if ((date = websGetDateString(&sbuf)) != NULL) {
websWrite(wp, T("Last-modified: %s\r\n"), date);
bfree(B_L, date);
}
bytes = sbuf.size;
}
if (bytes) {
websWrite(wp, T("Content-length: %d\r\n"), bytes);
websSetRequestBytes(wp, bytes);
}
websWrite(wp, T("Content-type: %s\r\n"), websGetRequestType(wp));
if ((flags & WEBS_KEEP_ALIVE) && !(flags & WEBS_ASP)) {
websWrite(wp, T("Connection: keep-alive\r\n"));
}
websWrite(wp, T("\r\n"));
/*
* All done if the browser did a HEAD request
*/
if (flags & WEBS_HEAD_REQUEST) {
websDone(wp, 200);
return 1;
}
/*
* Evaluate ASP requests
*/
if (flags & WEBS_ASP) {
if (websAspRequest(wp, lpath) < 0) {
return 1;
}
websDone(wp, 200);
return 1;
}
#ifdef WEBS_SSL_SUPPORT
if (wp->flags & WEBS_SECURE) {
websDefaultWriteEvent(wp);
} else {
websSetRequestSocketHandler(wp, SOCKET_WRITABLE, websDefaultWriteEvent);
}
#else
/*
* For normal web documents, return the data via background write
*/
websSetRequestSocketHandler(wp, SOCKET_WRITABLE, websDefaultWriteEvent);
#endif
return 1;
}
/******************************************************************************/
/*
* Validate the URL path and process ".." path segments. Return -1 if the URL
* is bad.
*/
int websValidateUrl(webs_t wp, char_t *path)
{
char_t *parts[64]; /* Array of ptr's to URL parts */
char_t *token, *dir, *lpath;
int i, len, npart;
a_assert(websValid(wp));
a_assert(path);
dir = websGetRequestDir(wp);
if (dir == NULL || *dir == '\0') {
return -1;
}
/*
* Copy the string so we don't destroy the original
*/
path = bstrdup(B_L, path);
websDecodeUrl(path, path, gstrlen(path));
len = npart = 0;
parts[0] = NULL;
/*
* 22 Jul 02 -- there were reports that a directory traversal exploit was
* possible in the WebServer running under Windows if directory paths
* outside the server's specified root web were given by URL-encoding the
* backslash character, like:
*
* GoAhead is vulnerable to a directory traversal bug. A request such as
*
* GoAhead-server/../../../../../../../ results in an error message
* 'Cannot open URL'.
* However, by encoding the '/' character, it is possible to break out of
* the
* web root and read arbitrary files from the server.
* Hence a request like:
*
* GoAhead-server/..%5C..%5C..%5C..%5C..%5C..%5C/winnt/win.ini returns the
* contents of the win.ini file.
* (Note that the description uses forward slashes (0x2F), but the example
* uses backslashes (0x5C). In my tests, forward slashes are correctly
* trapped, but backslashes are not. The code below substitutes forward
* slashes for backslashes before attempting to validate that there are no
* unauthorized paths being accessed.
*/
token = gstrchr(path, '\\');
while (token != NULL)
{
*token = '/';
token = gstrchr(token, '\\');
}
token = gstrtok(path, T("/"));
/*
* Look at each directory segment and process "." and ".." segments
* Don't allow the browser to pop outside the root web.
*/
while (token != NULL) {
if (gstrcmp(token, T("..")) == 0) {
if (npart > 0) {
npart--;
}
} else if (gstrcmp(token, T(".")) != 0) {
parts[npart] = token;
len += gstrlen(token) + 1;
npart++;
}
token = gstrtok(NULL, T("/"));
}
/*
* Create local path for document. Need extra space all "/" and null.
*/
if (npart || (gstrcmp(path, T("/")) == 0) || (path[0] == '\0')) {
lpath = balloc(B_L, (gstrlen(dir) + 1 + len + 1) * sizeof(char_t));
gstrcpy(lpath, dir);
for (i = 0; i < npart; i++) {
gstrcat(lpath, T("/"));
gstrcat(lpath, parts[i]);
}
websSetRequestLpath(wp, lpath);
bfree(B_L, path);
bfree(B_L, lpath);
} else {
bfree(B_L, path);
return -1;
}
return 0;
}
/******************************************************************************/
/*
* Do output back to the browser in the background. This is a socket
* write handler.
*/
static void websDefaultWriteEvent(webs_t wp)
{
int len, wrote, flags, bytes, written;
char *buf;
a_assert(websValid(wp));
flags = websGetRequestFlags(wp);
websSetTimeMark(wp);
wrote = bytes = 0;
written = websGetRequestWritten(wp);
/*
* We only do this for non-ASP documents
*/
if ( !(flags & WEBS_ASP)) {
bytes = websGetRequestBytes(wp);
/*
* Note: websWriteDataNonBlock may return less than we wanted. It will
* return -1 on a socket error
*/
if ((buf = balloc(B_L, PAGE_READ_BUFSIZE)) == NULL) {
websError(wp, 200, T("Can't get memory"));
} else {
while ((len = websPageReadData(wp, buf, PAGE_READ_BUFSIZE)) > 0) {
if ((wrote = websWriteDataNonBlock(wp, buf, len)) < 0) {
break;
}
written += wrote;
if (wrote != len) {
websPageSeek(wp, - (len - wrote));
break;
}
}
/*
* Safety. If we are at EOF, we must be done
*/
if (len == 0) {
a_assert(written >= bytes);
written = bytes;
}
bfree(B_L, buf);
}
}
/*
* We're done if an error, or all bytes output
*/
websSetRequestWritten(wp, written);
if (wrote < 0 || written >= bytes) {
websDone(wp, 200);
}
}
/******************************************************************************/
/*
* Closing down. Free resources.
*/
void websDefaultClose()
{
if (websDefaultPage) {
bfree(B_L, websDefaultPage);
websDefaultPage = NULL;
}
if (websDefaultDir) {
bfree(B_L, websDefaultDir);
websDefaultDir = NULL;
}
}
/******************************************************************************/
/*
* Get the default page for URL requests ending in "/"
*/
char_t *websGetDefaultPage()
{
return websDefaultPage;
}
/******************************************************************************/
/*
* Get the default web directory
*/
char_t *websGetDefaultDir()
{
return websDefaultDir;
}
/******************************************************************************/
/*
* Set the default page for URL requests ending in "/"
*/
void websSetDefaultPage(char_t *page)
{
a_assert(page && *page);
if (websDefaultPage) {
bfree(B_L, websDefaultPage);
}
websDefaultPage = bstrdup(B_L, page);
}
/******************************************************************************/
/*
* Set the default web directory
*/
void websSetDefaultDir(char_t *dir)
{
a_assert(dir && *dir);
if (websDefaultDir) {
bfree(B_L, websDefaultDir);
}
websDefaultDir = bstrdup(B_L, dir);
}
/******************************************************************************/

View File

@@ -1,46 +0,0 @@
/*
* ej.h -- Ejscript(TM) header
*
* Copyright (c) GoAhead Software Inc., 1992-2000. All Rights Reserved.
*
* See the file "license.txt" for information on usage and redistribution
*
* $Id$
*/
#ifndef _h_EJ
#define _h_EJ 1
/******************************** Description *********************************/
/*
* GoAhead Ejscript(TM) header. This defines the Ejscript API and internal
* structures.
*/
/********************************* Includes ***********************************/
#ifndef UEMF
#include "basic/basic.h"
#include "emf/emf.h"
#else
#include "uemf.h"
#endif
/********************************** Defines ***********************************/
/******************************** Prototypes **********************************/
extern int ejArgs(int argc, char_t **argv, char_t *fmt, ...);
extern void ejSetResult(int eid, char_t *s);
extern int ejOpenEngine(sym_fd_t variables, sym_fd_t functions);
extern void ejCloseEngine(int eid);
extern int ejSetGlobalFunction(int eid, char_t *name,
int (*fn)(int eid, void *handle, int argc, char_t **argv));
extern void ejSetVar(int eid, char_t *var, char_t *value);
extern int ejGetVar(int eid, char_t *var, char_t **value);
extern char_t *ejEval(int eid, char_t *script, char_t **emsg);
#endif /* _h_EJ */
/*****************************************************************************/

View File

@@ -1,230 +0,0 @@
/*
* ejIntrn.h -- Ejscript(TM) header
*
* Copyright (c) GoAhead Software, Inc., 1992-2000
*
* See the file "license.txt" for information on usage and redistribution
*
* $Id$
*/
#ifndef _h_EJINTERNAL
#define _h_EJINTERNAL 1
/******************************** Description *********************************/
/*
* GoAhead Ejscript(TM) header. This defines the Ejscript API and internal
* structures.
*/
/********************************* Includes ***********************************/
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#ifdef CE
#ifndef UEMF
#include <io.h>
#endif
#endif
#ifdef LYNX
#include <unistd.h>
#endif
#ifdef QNX4
#include <dirent.h>
#endif
#ifdef UEMF
#include "uemf.h"
#else
#include <param.h>
#include <stat.h>
#include "basic/basicInternal.h"
#include "emf/emfInternal.h"
#endif
#include "ej.h"
/********************************** Defines ***********************************/
/*
* Constants
*/
#define EJ_INC 110 /* Growth for tags/tokens */
#define EJ_SCRIPT_INC 1023 /* Growth for ej scripts */
#define EJ_OFFSET 1 /* hAlloc doesn't like 0 entries */
#define EJ_MAX_RECURSE 100 /* Sanity for maximum recursion */
/*
* Ejscript Lexical analyser tokens
*/
#define TOK_ERR -1 /* Any error */
#define TOK_LPAREN 1 /* ( */
#define TOK_RPAREN 2 /* ) */
#define TOK_IF 3 /* if */
#define TOK_ELSE 4 /* else */
#define TOK_LBRACE 5 /* { */
#define TOK_RBRACE 6 /* } */
#define TOK_LOGICAL 7 /* ||, &&, ! */
#define TOK_EXPR 8 /* +, -, /, % */
#define TOK_SEMI 9 /* ; */
#define TOK_LITERAL 10 /* literal string */
#define TOK_FUNCTION 11 /* function name */
#define TOK_NEWLINE 12 /* newline white space */
#define TOK_ID 13 /* function name */
#define TOK_EOF 14 /* End of script */
#define TOK_COMMA 15 /* Comma */
#define TOK_VAR 16 /* var */
#define TOK_ASSIGNMENT 17 /* = */
#define TOK_FOR 18 /* for */
#define TOK_INC_DEC 19 /* ++, -- */
#define TOK_RETURN 20 /* return */
/*
* Expression operators
*/
#define EXPR_LESS 1 /* < */
#define EXPR_LESSEQ 2 /* <= */
#define EXPR_GREATER 3 /* > */
#define EXPR_GREATEREQ 4 /* >= */
#define EXPR_EQ 5 /* == */
#define EXPR_NOTEQ 6 /* != */
#define EXPR_PLUS 7 /* + */
#define EXPR_MINUS 8 /* - */
#define EXPR_DIV 9 /* / */
#define EXPR_MOD 10 /* % */
#define EXPR_LSHIFT 11 /* << */
#define EXPR_RSHIFT 12 /* >> */
#define EXPR_MUL 13 /* * */
#define EXPR_ASSIGNMENT 14 /* = */
#define EXPR_INC 15 /* ++ */
#define EXPR_DEC 16 /* -- */
#define EXPR_BOOL_COMP 17 /* ! */
/*
* Conditional operators
*/
#define COND_AND 1 /* && */
#define COND_OR 2 /* || */
#define COND_NOT 3 /* ! */
/*
* States
*/
#define STATE_ERR -1 /* Error state */
#define STATE_EOF 1 /* End of file */
#define STATE_COND 2 /* Parsing a "(conditional)" stmt */
#define STATE_COND_DONE 3
#define STATE_RELEXP 4 /* Parsing a relational expr */
#define STATE_RELEXP_DONE 5
#define STATE_EXPR 6 /* Parsing an expression */
#define STATE_EXPR_DONE 7
#define STATE_STMT 8 /* Parsing General statement */
#define STATE_STMT_DONE 9
#define STATE_STMT_BLOCK_DONE 10 /* End of block "}" */
#define STATE_ARG_LIST 11 /* Function arg list */
#define STATE_ARG_LIST_DONE 12
#define STATE_DEC_LIST 16 /* Declaration list */
#define STATE_DEC_LIST_DONE 17
#define STATE_DEC 18
#define STATE_DEC_DONE 19
#define STATE_RET 20 /* Return statement */
#define STATE_BEGIN STATE_STMT
/*
* Flags. Used in ej_t and as parameter to parse()
*/
#define FLAGS_EXE 0x1 /* Execute statements */
#define FLAGS_VARIABLES 0x2 /* Allocated variables store */
#define FLAGS_FUNCTIONS 0x4 /* Allocated function store */
/*
* Function call structure
*/
typedef struct {
char_t *fname; /* Function name */
char_t **args; /* Args for function (halloc) */
int nArgs; /* Number of args */
} ejfunc_t;
/*
* EJ evaluation block structure
*/
typedef struct ejEval {
ringq_t tokbuf; /* Current token */
ringq_t script; /* Input script for parsing */
char_t *putBackToken; /* Putback token string */
int putBackTokenId; /* Putback token ID */
char_t *line; /* Current line */
int lineLength; /* Current line length */
int lineNumber; /* Parse line number */
int lineColumn; /* Column in line */
} ejinput_t;
/*
* Per Ejscript session structure
*/
typedef struct ej {
ejinput_t *input; /* Input evaluation block */
sym_fd_t functions; /* Symbol table for functions */
sym_fd_t *variables; /* hAlloc list of variables */
int variableMax; /* Number of entries */
ejfunc_t *func; /* Current function */
char_t *result; /* Current expression result */
char_t *error; /* Error message */
char_t *token; /* Pointer to token string */
int tid; /* Current token id */
int eid; /* Halloc handle */
int flags; /* Flags */
int userHandle; /* User defined handle */
} ej_t;
/******************************** Prototypes **********************************/
extern int ejOpenBlock(int eid);
extern int ejCloseBlock(int eid, int vid);
extern char_t *ejEvalBlock(int eid, char_t *script, char_t **emsg);
#ifndef __NO_EJ_FILE
extern char_t *ejEvalFile(int eid, char_t *path, char_t **emsg);
#endif
extern int ejRemoveGlobalFunction(int eid, char_t *name);
extern void *ejGetGlobalFunction(int eid, char_t *name);
extern int ejSetGlobalFunctionDirect(sym_fd_t functions, char_t *name,
int (*fn)(int eid, void *handle, int argc, char_t **argv));
extern void ejError(ej_t* ep, char_t* fmt, ...);
extern void ejSetUserHandle(int eid, int handle);
extern int ejGetUserHandle(int eid);
extern int ejGetLineNumber(int eid);
extern char_t *ejGetResult(int eid);
extern void ejSetLocalVar(int eid, char_t *var, char_t *value);
extern void ejSetGlobalVar(int eid, char_t *var, char_t *value);
extern int ejLexOpen(ej_t* ep);
extern void ejLexClose(ej_t* ep);
extern int ejLexOpenScript(ej_t* ep, char_t *script);
extern void ejLexCloseScript(ej_t* ep);
extern void ejLexSaveInputState(ej_t* ep, ejinput_t* state);
extern void ejLexFreeInputState(ej_t* ep, ejinput_t* state);
extern void ejLexRestoreInputState(ej_t* ep, ejinput_t* state);
extern int ejLexGetToken(ej_t* ep, int state);
extern void ejLexPutbackToken(ej_t* ep, int tid, char_t *string);
extern sym_fd_t ejGetVariableTable(int eid);
extern sym_fd_t ejGetFunctionTable(int eid);
extern int ejEmfOpen(int eid);
extern void ejEmfClose(int eid);
extern int ejEmfDbRead(int eid, void *handle, int argc, char_t **argv);
extern int ejEmfDbReadKeyed(int eid, void *handle, int argc, char_t **argv);
extern int ejEmfDbTableGetNrow(int eid, void *handle, int argc, char_t **argv);
extern int ejEmfDbDeleteRow(int eid, void *handle, int argc, char_t **argv);
extern int ejEmfTrace(int eid, void *handle, int argc, char_t **argv);
extern int ejEmfDbWrite(int eid, void *handle, int argc, char_t **argv);
extern int ejEmfDbCollectTable(int eid, void *handle, int argc, char_t **argv);
#endif /* _h_EJINTERNAL */

View File

@@ -1,721 +0,0 @@
/*
* ejlex.c -- Ejscript(TM) Lexical Analyser
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* Ejscript lexical analyser. This implementes a lexical analyser for a
* a subset of the JavaScript language.
*/
/********************************** Includes **********************************/
#include "ejIntrn.h"
#ifdef UEMF
#include "uemf.h"
#else
#include "basic/basicInternal.h"
#endif
/********************************** Defines ***********************************/
#define OCTAL 8
#define HEX 16
/****************************** Forward Declarations **************************/
static int getLexicalToken(ej_t* ep, int state);
static int tokenAddChar(ej_t *ep, int c);
static int inputGetc(ej_t* ep);
static void inputPutback(ej_t* ep, int c);
static int charConvert(ej_t* ep, int base, int maxDig);
/************************************* Code ***********************************/
/*
* Setup the lexical analyser
*/
int ejLexOpen(ej_t* ep)
{
return 0;
}
/******************************************************************************/
/*
* Close the lexicial analyser
*/
void ejLexClose(ej_t* ep)
{
}
/******************************************************************************/
/*
* Open a new input script
*/
int ejLexOpenScript(ej_t* ep, char_t *script)
{
ejinput_t *ip;
a_assert(ep);
a_assert(script);
if ((ep->input = balloc(B_L, sizeof(ejinput_t))) == NULL) {
return -1;
}
ip = ep->input;
memset(ip, 0, sizeof(*ip));
a_assert(ip);
a_assert(ip->putBackToken == NULL);
a_assert(ip->putBackTokenId == 0);
/*
* Create the parse token buffer and script buffer
*/
if (ringqOpen(&ip->tokbuf, EJ_INC, -1) < 0) {
return -1;
}
if (ringqOpen(&ip->script, EJ_SCRIPT_INC, -1) < 0) {
return -1;
}
/*
* Put the Ejscript into a ring queue for easy parsing
*/
ringqPutStr(&ip->script, script);
ip->lineNumber = 1;
ip->lineLength = 0;
ip->lineColumn = 0;
ip->line = NULL;
return 0;
}
/******************************************************************************/
/*
* Close the input script
*/
void ejLexCloseScript(ej_t* ep)
{
ejinput_t *ip;
a_assert(ep);
ip = ep->input;
a_assert(ip);
if (ip->putBackToken) {
bfree(B_L, ip->putBackToken);
ip->putBackToken = NULL;
}
ip->putBackTokenId = 0;
if (ip->line) {
bfree(B_L, ip->line);
ip->line = NULL;
}
ringqClose(&ip->tokbuf);
ringqClose(&ip->script);
bfree(B_L, ip);
}
/******************************************************************************/
/*
* Save the input state
*/
void ejLexSaveInputState(ej_t* ep, ejinput_t* state)
{
ejinput_t *ip;
a_assert(ep);
ip = ep->input;
a_assert(ip);
*state = *ip;
if (ip->putBackToken) {
state->putBackToken = bstrdup(B_L, ip->putBackToken);
}
}
/******************************************************************************/
/*
* Restore the input state
*/
void ejLexRestoreInputState(ej_t* ep, ejinput_t* state)
{
ejinput_t *ip;
a_assert(ep);
ip = ep->input;
a_assert(ip);
ip->tokbuf = state->tokbuf;
ip->script = state->script;
ip->putBackTokenId = state->putBackTokenId;
if (ip->putBackToken) {
bfree(B_L, ip->putBackToken);
}
if (state->putBackToken) {
ip->putBackToken = bstrdup(B_L, state->putBackToken);
}
}
/******************************************************************************/
/*
* Free a saved input state
*/
void ejLexFreeInputState(ej_t* ep, ejinput_t* state)
{
if (state->putBackToken) {
bfree(B_L, state->putBackToken);
state->putBackToken = NULL;
}
}
/******************************************************************************/
/*
* Get the next Ejscript token
*/
int ejLexGetToken(ej_t* ep, int state)
{
ep->tid = getLexicalToken(ep, state);
/*
* commented out 04 Apr 02 Bg Porter -- we found a case where very long
* arguments to write() were being corrupted downstream in the trace call
* (the ep->token pointer was being overwritten with the trace message.
* restore this if it's useful for your debugging.
trace(9, T("ejGetToken: %d, \"%s\"\n"), ep->tid, ep->token);
*/
return ep->tid;
}
/******************************************************************************/
/*
* Get the next Ejscript token
*/
static int getLexicalToken(ej_t* ep, int state)
{
ringq_t *inq, *tokq;
ejinput_t* ip;
int done, tid, c, quote, style;
a_assert(ep);
ip = ep->input;
a_assert(ip);
inq = &ip->script;
tokq = &ip->tokbuf;
ep->tid = -1;
tid = -1;
ep->token = T("");
ringqFlush(tokq);
if (ip->putBackTokenId > 0) {
ringqPutStr(tokq, ip->putBackToken);
tid = ip->putBackTokenId;
ip->putBackTokenId = 0;
ep->token = (char_t*) tokq->servp;
return tid;
}
if ((c = inputGetc(ep)) < 0) {
return TOK_EOF;
}
for (done = 0; !done; ) {
switch (c) {
case -1:
return TOK_EOF;
case ' ':
case '\t':
case '\r':
do {
if ((c = inputGetc(ep)) < 0)
break;
} while (c == ' ' || c == '\t' || c == '\r');
break;
case '\n':
return TOK_NEWLINE;
case '(':
tokenAddChar(ep, c);
return TOK_LPAREN;
case ')':
tokenAddChar(ep, c);
return TOK_RPAREN;
case '{':
tokenAddChar(ep, c);
return TOK_LBRACE;
case '}':
tokenAddChar(ep, c);
return TOK_RBRACE;
case '+':
if ((c = inputGetc(ep)) < 0) {
ejError(ep, T("Syntax Error"));
return TOK_ERR;
}
if (c != '+' ) {
inputPutback(ep, c);
tokenAddChar(ep, EXPR_PLUS);
return TOK_EXPR;
}
tokenAddChar(ep, EXPR_INC);
return TOK_INC_DEC;
case '-':
if ((c = inputGetc(ep)) < 0) {
ejError(ep, T("Syntax Error"));
return TOK_ERR;
}
if (c != '-' ) {
inputPutback(ep, c);
tokenAddChar(ep, EXPR_MINUS);
return TOK_EXPR;
}
tokenAddChar(ep, EXPR_DEC);
return TOK_INC_DEC;
case '*':
tokenAddChar(ep, EXPR_MUL);
return TOK_EXPR;
case '%':
tokenAddChar(ep, EXPR_MOD);
return TOK_EXPR;
case '/':
/*
* Handle the division operator and comments
*/
if ((c = inputGetc(ep)) < 0) {
ejError(ep, T("Syntax Error"));
return TOK_ERR;
}
if (c != '*' && c != '/') {
inputPutback(ep, c);
tokenAddChar(ep, EXPR_DIV);
return TOK_EXPR;
}
style = c;
/*
* Eat comments. Both C and C++ comment styles are supported.
*/
while (1) {
if ((c = inputGetc(ep)) < 0) {
ejError(ep, T("Syntax Error"));
return TOK_ERR;
}
if (c == '\n' && style == '/') {
break;
} else if (c == '*') {
c = inputGetc(ep);
if (style == '/') {
if (c == '\n') {
break;
}
} else {
if (c == '/') {
break;
}
}
}
}
/*
* Continue looking for a token, so get the next character
*/
if ((c = inputGetc(ep)) < 0) {
return TOK_EOF;
}
break;
case '<': /* < and <= */
if ((c = inputGetc(ep)) < 0) {
ejError(ep, T("Syntax Error"));
return TOK_ERR;
}
if (c == '<') {
tokenAddChar(ep, EXPR_LSHIFT);
return TOK_EXPR;
} else if (c == '=') {
tokenAddChar(ep, EXPR_LESSEQ);
return TOK_EXPR;
}
tokenAddChar(ep, EXPR_LESS);
inputPutback(ep, c);
return TOK_EXPR;
case '>': /* > and >= */
if ((c = inputGetc(ep)) < 0) {
ejError(ep, T("Syntax Error"));
return TOK_ERR;
}
if (c == '>') {
tokenAddChar(ep, EXPR_RSHIFT);
return TOK_EXPR;
} else if (c == '=') {
tokenAddChar(ep, EXPR_GREATEREQ);
return TOK_EXPR;
}
tokenAddChar(ep, EXPR_GREATER);
inputPutback(ep, c);
return TOK_EXPR;
case '=': /* "==" */
if ((c = inputGetc(ep)) < 0) {
ejError(ep, T("Syntax Error"));
return TOK_ERR;
}
if (c == '=') {
tokenAddChar(ep, EXPR_EQ);
return TOK_EXPR;
}
inputPutback(ep, c);
return TOK_ASSIGNMENT;
case '!': /* "!=" or "!"*/
if ((c = inputGetc(ep)) < 0) {
ejError(ep, T("Syntax Error"));
return TOK_ERR;
}
if (c == '=') {
tokenAddChar(ep, EXPR_NOTEQ);
return TOK_EXPR;
}
inputPutback(ep, c);
tokenAddChar(ep, EXPR_BOOL_COMP);
return TOK_EXPR;
case ';':
tokenAddChar(ep, c);
return TOK_SEMI;
case ',':
tokenAddChar(ep, c);
return TOK_COMMA;
case '|': /* "||" */
if ((c = inputGetc(ep)) < 0 || c != '|') {
ejError(ep, T("Syntax Error"));
return TOK_ERR;
}
tokenAddChar(ep, COND_OR);
return TOK_LOGICAL;
case '&': /* "&&" */
if ((c = inputGetc(ep)) < 0 || c != '&') {
ejError(ep, T("Syntax Error"));
return TOK_ERR;
}
tokenAddChar(ep, COND_AND);
return TOK_LOGICAL;
case '\"': /* String quote */
case '\'':
quote = c;
if ((c = inputGetc(ep)) < 0) {
ejError(ep, T("Syntax Error"));
return TOK_ERR;
}
while (c != quote) {
/*
* check for escape sequence characters
*/
if (c == '\\') {
c = inputGetc(ep);
if (gisdigit(c)) {
/*
* octal support, \101 maps to 65 = 'A'. put first char
* back so converter will work properly.
*/
inputPutback(ep, c);
c = charConvert(ep, OCTAL, 3);
} else {
switch (c) {
case 'n':
c = '\n'; break;
case 'b':
c = '\b'; break;
case 'f':
c = '\f'; break;
case 'r':
c = '\r'; break;
case 't':
c = '\t'; break;
case 'x':
/*
* hex support, \x41 maps to 65 = 'A'
*/
c = charConvert(ep, HEX, 2);
break;
case 'u':
/*
* unicode support, \x0401 maps to 65 = 'A'
*/
c = charConvert(ep, HEX, 2);
c = c*16 + charConvert(ep, HEX, 2);
break;
case '\'':
case '\"':
case '\\':
break;
default:
ejError(ep, T("Invalid Escape Sequence"));
return TOK_ERR;
}
}
if (tokenAddChar(ep, c) < 0) {
return TOK_ERR;
}
} else {
if (tokenAddChar(ep, c) < 0) {
return TOK_ERR;
}
}
if ((c = inputGetc(ep)) < 0) {
ejError(ep, T("Unmatched Quote"));
return TOK_ERR;
}
}
return TOK_LITERAL;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
do {
if (tokenAddChar(ep, c) < 0) {
return TOK_ERR;
}
if ((c = inputGetc(ep)) < 0)
break;
} while (gisdigit(c));
inputPutback(ep, c);
return TOK_LITERAL;
default:
/*
* Identifiers or a function names
*/
while (1) {
if (c == '\\') {
/*
* just ignore any \ characters.
*/
} else if (tokenAddChar(ep, c) < 0) {
break;
}
if ((c = inputGetc(ep)) < 0) {
break;
}
if (!gisalnum(c) && c != '$' && c != '_' &&
c != '\\') {
break;
}
}
if (! gisalpha(*tokq->servp) && *tokq->servp != '$' &&
*tokq->servp != '_') {
ejError(ep, T("Invalid identifier %s"), tokq->servp);
return TOK_ERR;
}
/*
* Check for reserved words (only "if", "else", "var", "for"
* and "return" at the moment)
*/
if (state == STATE_STMT) {
if (gstrcmp(ep->token, T("if")) == 0) {
return TOK_IF;
} else if (gstrcmp(ep->token, T("else")) == 0) {
return TOK_ELSE;
} else if (gstrcmp(ep->token, T("var")) == 0) {
return TOK_VAR;
} else if (gstrcmp(ep->token, T("for")) == 0) {
return TOK_FOR;
} else if (gstrcmp(ep->token, T("return")) == 0) {
if ((c == ';') || (c == '(')) {
inputPutback(ep, c);
}
return TOK_RETURN;
}
}
/*
* Skip white space after token to find out whether this is
* a function or not.
*/
while (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
if ((c = inputGetc(ep)) < 0)
break;
}
tid = (c == '(') ? TOK_FUNCTION : TOK_ID;
done++;
}
}
/*
* Putback the last extra character for next time
*/
inputPutback(ep, c);
return tid;
}
/******************************************************************************/
/*
* Putback the last token read
*/
void ejLexPutbackToken(ej_t* ep, int tid, char_t *string)
{
ejinput_t* ip;
a_assert(ep);
ip = ep->input;
a_assert(ip);
if (ip->putBackToken) {
bfree(B_L, ip->putBackToken);
}
ip->putBackTokenId = tid;
ip->putBackToken = bstrdup(B_L, string);
}
/******************************************************************************/
/*
* Add a character to the token ringq buffer
*/
static int tokenAddChar(ej_t *ep, int c)
{
ejinput_t* ip;
a_assert(ep);
ip = ep->input;
a_assert(ip);
if (ringqPutc(&ip->tokbuf, (char_t) c) < 0) {
ejError(ep, T("Token too big"));
return -1;
}
* ((char_t*) ip->tokbuf.endp) = '\0';
ep->token = (char_t*) ip->tokbuf.servp;
return 0;
}
/******************************************************************************/
/*
* Get another input character
*/
static int inputGetc(ej_t* ep)
{
ejinput_t *ip;
int c, len;
a_assert(ep);
ip = ep->input;
if ((len = ringqLen(&ip->script)) == 0) {
return -1;
}
c = ringqGetc(&ip->script);
if (c == '\n') {
ip->lineNumber++;
ip->lineColumn = 0;
} else {
if ((ip->lineColumn + 2) >= ip->lineLength) {
ip->lineLength += EJ_INC;
ip->line = brealloc(B_L, ip->line, ip->lineLength * sizeof(char_t));
}
ip->line[ip->lineColumn++] = c;
ip->line[ip->lineColumn] = '\0';
}
return c;
}
/******************************************************************************/
/*
* Putback a character onto the input queue
*/
static void inputPutback(ej_t* ep, int c)
{
ejinput_t *ip;
a_assert(ep);
ip = ep->input;
ringqInsertc(&ip->script, (char_t) c);
ip->lineColumn--;
ip->line[ip->lineColumn] = '\0';
}
/******************************************************************************/
/*
* Convert a hex or octal character back to binary, return original char if
* not a hex digit
*/
static int charConvert(ej_t* ep, int base, int maxDig)
{
int i, c, lval, convChar;
lval = 0;
for (i = 0; i < maxDig; i++) {
if ((c = inputGetc(ep)) < 0) {
break;
}
/*
* Initialize to out of range value
*/
convChar = base;
if (gisdigit(c)) {
convChar = c - '0';
} else if (c >= 'a' && c <= 'f') {
convChar = c - 'a' + 10;
} else if (c >= 'A' && c <= 'F') {
convChar = c - 'A' + 10;
}
/*
* if unexpected character then return it to buffer.
*/
if (convChar >= base) {
inputPutback(ep, c);
break;
}
lval = (lval * base) + convChar;
}
return lval;
}
/******************************************************************************/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,101 +0,0 @@
/*
* emfdb.h -- EMF database compatability functions for GoAhead WebServer.
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* Emf-like textfile database support for WebServer 2.1.
*/
/********************************* Includes ***********************************/
#ifndef _h_EMFDB
#define _h_EMFDB 1
#ifndef UEMF
#include "basic/basic.h"
#include "emf/emf.h"
#else
#include "uemf.h"
#endif
/********************************* Defines ************************************/
#define T_INT 0
#define T_STRING 1
#define DB_OK 0
#define DB_ERR_GENERAL -1
#define DB_ERR_COL_NOT_FOUND -2
#define DB_ERR_COL_DELETED -3
#define DB_ERR_ROW_NOT_FOUND -4
#define DB_ERR_ROW_DELETED -5
#define DB_ERR_TABLE_NOT_FOUND -6
#define DB_ERR_TABLE_DELETED -7
#define DB_ERR_BAD_FORMAT -8
typedef struct dbTable_s {
char_t *name;
int nColumns;
char_t **columnNames;
int *columnTypes;
int nRows;
int **rows;
} dbTable_t;
/********************************** Prototypes ********************************/
/*
* Add a schema to the module-internal schema database
*/
extern int dbRegisterDBSchema(dbTable_t *sTable);
extern int dbOpen(char_t *databasename, char_t *filename,
int (*gettime)(int did), int flags);
extern void dbClose(int did);
extern int dbGetTableId(int did, char_t *tname);
extern char_t *dbGetTableName(int did, int tid);
extern int dbReadInt(int did, char_t *table, char_t *column, int row,
int *returnValue);
extern int dbReadStr(int did, char_t *table, char_t *column, int row,
char_t **returnValue);
extern int dbWriteInt(int did, char_t *table, char_t *column, int row,
int idata);
extern int dbWriteStr(int did, char_t *table, char_t *column, int row,
char_t *s);
extern int dbAddRow(int did, char_t *table);
extern int dbDeleteRow(int did, char_t *table, int rid);
extern int dbSetTableNrow(int did, char_t *table, int nNewRows);
extern int dbGetTableNrow(int did, char_t *table);
/*
* Dump the contents of a database to file
*/
extern int dbSave(int did, char_t *filename, int flags);
/*
* Load the contents of a database to file
*/
extern int dbLoad(int did, char_t *filename, int flags);
/*
* Search for a data in a given column
*/
extern int dbSearchStr(int did, char_t *table, char_t *column,
char_t *value, int flags);
extern void dbZero(int did);
extern char_t *basicGetProductDir();
extern void basicSetProductDir(char_t *proddir);
#endif /* _h_EMFDB */
/******************************************************************************/

View File

@@ -1,168 +0,0 @@
/*
* form.c -- Form processing (in-memory CGI) for the GoAhead Web server
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/********************************** Description *******************************/
/*
* This module implements the /goform handler. It emulates CGI processing
* but performs this in-process and not as an external process. This enables
* a very high performance implementation with easy parsing and decoding
* of query strings and posted data.
*/
/*********************************** Includes *********************************/
#include "wsIntrn.h"
/************************************ Locals **********************************/
static sym_fd_t formSymtab = -1; /* Symbol table for form handlers */
/************************************* Code ***********************************/
/*
* Process a form request. Returns 1 always to indicate it handled the URL
*/
int websFormHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg,
char_t *url, char_t *path, char_t *query)
{
sym_t *sp;
char_t formBuf[FNAMESIZE];
char_t *cp, *formName;
int (*fn)(void *sock, char_t *path, char_t *args);
a_assert(websValid(wp));
a_assert(url && *url);
a_assert(path && *path == '/');
websStats.formHits++;
/*
* Extract the form name
*/
gstrncpy(formBuf, path, TSZ(formBuf));
if ((formName = gstrchr(&formBuf[1], '/')) == NULL) {
websError(wp, 200, T("Missing form name"));
return 1;
}
formName++;
if ((cp = gstrchr(formName, '/')) != NULL) {
*cp = '\0';
}
/*
* Lookup the C form function first and then try tcl (no javascript support
* yet).
*/
sp = symLookup(formSymtab, formName);
if (sp == NULL) {
websError(wp, 200, T("Form %s is not defined"), formName);
} else {
fn = (int (*)(void *, char_t *, char_t *)) sp->content.value.integer;
a_assert(fn);
if (fn) {
/*
* For good practice, forms must call websDone()
*/
(*fn)((void*) wp, formName, query);
/*
* Remove the test to force websDone, since this prevents
* the server "push" from a form>
*/
#if 0 /* push */
if (websValid(wp)) {
websError(wp, 200, T("Form didn't call websDone"));
}
#endif /* push */
}
}
return 1;
}
/******************************************************************************/
/*
* Define a form function in the "form" map space.
*/
int websFormDefine(char_t *name, void (*fn)(webs_t wp, char_t *path,
char_t *query))
{
a_assert(name && *name);
a_assert(fn);
if (fn == NULL) {
return -1;
}
symEnter(formSymtab, name, valueInteger((int) fn), (int) NULL);
return 0;
}
/******************************************************************************/
/*
* Open the symbol table for forms.
*/
void websFormOpen()
{
formSymtab = symOpen(WEBS_SYM_INIT);
}
/******************************************************************************/
/*
* Close the symbol table for forms.
*/
void websFormClose()
{
if (formSymtab != -1) {
symClose(formSymtab);
formSymtab = -1;
}
}
/******************************************************************************/
/*
* Write a webs header. This is a convenience routine to write a common
* header for a form back to the browser.
*/
void websHeader(webs_t wp)
{
a_assert(websValid(wp));
websWrite(wp, T("HTTP/1.0 200 OK\n"));
/*
* By license terms the following line of code must not be modified
*/
websWrite(wp, T("Server: %s\r\n"), WEBS_NAME);
websWrite(wp, T("Pragma: no-cache\n"));
websWrite(wp, T("Cache-control: no-cache\n"));
websWrite(wp, T("Content-Type: text/html\n"));
websWrite(wp, T("\n"));
websWrite(wp, T("<html>\n"));
}
/******************************************************************************/
/*
* Write a webs footer
*/
void websFooter(webs_t wp)
{
a_assert(websValid(wp));
websWrite(wp, T("</html>\n"));
}
/******************************************************************************/

View File

@@ -1,194 +0,0 @@
/*
* h.c -- Handle allocation module
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* This module provides a simple API to allocate and free handles
* It maintains a dynamic array of pointers. These usually point to
* per-handle structures.
*/
/********************************* Includes ***********************************/
#ifdef UEMF
#include "uemf.h"
#else
#include "basic/basicInternal.h"
#endif
/********************************** Defines ***********************************/
/*
* The handle list stores the length of the list and the number of used
* handles in the first two words. These are hidden from the caller by
* returning a pointer to the third word to the caller
*/
#define H_LEN 0 /* First entry holds length of list */
#define H_USED 1 /* Second entry holds number of used */
#define H_OFFSET 2 /* Offset to real start of list */
#define H_INCR 16 /* Grow handle list in chunks this size */
/*********************************** Code *************************************/
/*
* Allocate a new file handle. On the first call, the caller must set the
* handle map to be a pointer to a null pointer. *map points to the second
* element in the handle array.
*/
#ifdef B_STATS
int HALLOC(B_ARGS_DEC, void ***map)
#else
int hAlloc(void ***map)
#endif
{
int *mp;
int handle, len, memsize, incr;
a_assert(map);
if (*map == NULL) {
incr = H_INCR;
memsize = (incr + H_OFFSET) * sizeof(void**);
#ifdef B_STATS
if ((mp = (int*) balloc(B_ARGS, memsize)) == NULL) {
#else
if ((mp = (int*) balloc(B_L, memsize)) == NULL) {
#endif
return -1;
}
memset(mp, 0, memsize);
mp[H_LEN] = incr;
mp[H_USED] = 0;
*map = (void**) &mp[H_OFFSET];
} else {
mp = &((*(int**)map)[-H_OFFSET]);
}
len = mp[H_LEN];
/*
* Find the first null handle
*/
if (mp[H_USED] < mp[H_LEN]) {
for (handle = 0; handle < len; handle++) {
if (mp[handle+H_OFFSET] == 0) {
mp[H_USED]++;
return handle;
}
}
} else {
handle = len;
}
/*
* No free handle so grow the handle list. Grow list in chunks of H_INCR.
*/
len += H_INCR;
memsize = (len + H_OFFSET) * sizeof(void**);
if ((mp = (int*) brealloc(B_L, (void*) mp, memsize)) == NULL) {
return -1;
}
*map = (void**) &mp[H_OFFSET];
mp[H_LEN] = len;
memset(&mp[H_OFFSET + len - H_INCR], 0, sizeof(int*) * H_INCR);
mp[H_USED]++;
return handle;
}
/******************************************************************************/
/*
* Free a handle. This function returns the value of the largest
* handle in use plus 1, to be saved as a max value.
*/
int hFree(void ***map, int handle)
{
int *mp;
int len;
a_assert(map);
mp = &((*(int**)map)[-H_OFFSET]);
a_assert(mp[H_LEN] >= H_INCR);
a_assert(mp[handle + H_OFFSET]);
a_assert(mp[H_USED]);
mp[handle + H_OFFSET] = 0;
if (--(mp[H_USED]) == 0) {
bfree(B_L, (void*) mp);
*map = NULL;
}
/*
* Find the greatest handle number in use.
*/
if (*map == NULL) {
handle = -1;
} else {
len = mp[H_LEN];
if (mp[H_USED] < mp[H_LEN]) {
for (handle = len - 1; handle >= 0; handle--) {
if (mp[handle + H_OFFSET])
break;
}
} else {
handle = len;
}
}
return handle + 1;
}
/******************************************************************************/
/*
* Allocate an entry in the halloc array.
*/
#ifdef B_STATS
int HALLOCENTRY(B_ARGS_DEC, void ***list, int *max, int size)
#else
int hAllocEntry(void ***list, int *max, int size)
#endif
{
char_t *cp;
int id;
a_assert(list);
a_assert(max);
#ifdef B_STATS
if ((id = HALLOC(B_ARGS, (void***) list)) < 0) {
#else
if ((id = hAlloc((void***) list)) < 0) {
#endif
return -1;
}
if (size > 0) {
#ifdef B_STATS
if ((cp = balloc(B_ARGS, size)) == NULL) {
#else
if ((cp = balloc(B_L, size)) == NULL) {
#endif
hFree(list, id);
return -1;
}
a_assert(cp);
memset(cp, 0, size);
(*list)[id] = (void*) cp;
}
if (id >= *max) {
*max = id + 1;
}
return id;
}
/******************************************************************************/

View File

@@ -1,411 +0,0 @@
/*
* handler.c -- URL handler support
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* This module implements a URL handler interface and API to permit
* the addition of user definable URL processors.
*/
/********************************* Includes ***********************************/
#include "wsIntrn.h"
/*********************************** Locals ***********************************/
static websUrlHandlerType *websUrlHandler; /* URL handler list */
static int websUrlHandlerMax; /* Number of entries */
static int urlHandlerOpenCount = 0; /* count of apps */
/**************************** Forward Declarations ****************************/
static int websUrlHandlerSort(const void *p1, const void *p2);
static int websPublishHandler(webs_t wp, char_t *urlPrefix, char_t *webDir,
int sid, char_t *url, char_t *path, char_t *query);
static char_t *websCondenseMultipleChars(char_t *strToCondense, char_t cCondense);
/*********************************** Code *************************************/
/*
* Initialize the URL handler module
*/
int websUrlHandlerOpen()
{
if (++urlHandlerOpenCount == 1) {
websAspOpen();
websUrlHandler = NULL;
websUrlHandlerMax = 0;
}
return 0;
}
/******************************************************************************/
/*
* Close the URL handler module
*/
void websUrlHandlerClose()
{
websUrlHandlerType *sp;
if (--urlHandlerOpenCount <= 0) {
websAspClose();
for (sp = websUrlHandler; sp < &websUrlHandler[websUrlHandlerMax];
sp++) {
bfree(B_L, sp->urlPrefix);
if (sp->webDir) {
bfree(B_L, sp->webDir);
}
}
bfree(B_L, websUrlHandler);
websUrlHandlerMax = 0;
}
}
/******************************************************************************/
/*
* Define a new URL handler. urlPrefix is the URL prefix to match. webDir is
* an optional root directory path for a web directory. arg is an optional
* arg to pass to the URL handler. flags defines the matching order. Valid
* flags include WEBS_HANDLER_LAST, WEBS_HANDLER_FIRST. If multiple users
* specify last or first, their order is defined alphabetically by the
* urlPrefix.
*/
int websUrlHandlerDefine(char_t *urlPrefix, char_t *webDir, int arg,
int (*handler)(webs_t wp, char_t *urlPrefix, char_t *webdir, int arg,
char_t *url, char_t *path, char_t *query), int flags)
{
websUrlHandlerType *sp;
int len;
a_assert(urlPrefix);
a_assert(handler);
/*
* Grow the URL handler array to create a new slot
*/
len = (websUrlHandlerMax + 1) * sizeof(websUrlHandlerType);
if ((websUrlHandler = brealloc(B_L, websUrlHandler, len)) == NULL) {
return -1;
}
sp = &websUrlHandler[websUrlHandlerMax++];
memset(sp, 0, sizeof(websUrlHandlerType));
sp->urlPrefix = bstrdup(B_L, urlPrefix);
sp->len = gstrlen(sp->urlPrefix);
if (webDir) {
sp->webDir = bstrdup(B_L, webDir);
} else {
sp->webDir = bstrdup(B_L, T(""));
}
sp->handler = handler;
sp->arg = arg;
sp->flags = flags;
/*
* Sort in decreasing URL length order observing the flags for first and last
*/
qsort(websUrlHandler, websUrlHandlerMax, sizeof(websUrlHandlerType),
websUrlHandlerSort);
return 0;
}
/******************************************************************************/
/*
* Delete an existing URL handler. We don't reclaim the space of the old
* handler, just NULL the entry. Return -1 if handler is not found.
*/
int websUrlHandlerDelete(int (*handler)(webs_t wp, char_t *urlPrefix,
char_t *webDir, int arg, char_t *url, char_t *path, char_t *query))
{
websUrlHandlerType *sp;
int i;
for (i = 0; i < websUrlHandlerMax; i++) {
sp = &websUrlHandler[i];
if (sp->handler == handler) {
sp->handler = NULL;
return 0;
}
}
return -1;
}
/******************************************************************************/
/*
* Sort in decreasing URL length order observing the flags for first and last
*/
static int websUrlHandlerSort(const void *p1, const void *p2)
{
websUrlHandlerType *s1, *s2;
int rc;
a_assert(p1);
a_assert(p2);
s1 = (websUrlHandlerType*) p1;
s2 = (websUrlHandlerType*) p2;
if ((s1->flags & WEBS_HANDLER_FIRST) || (s2->flags & WEBS_HANDLER_LAST)) {
return -1;
}
if ((s2->flags & WEBS_HANDLER_FIRST) || (s1->flags & WEBS_HANDLER_LAST)) {
return 1;
}
if ((rc = gstrcmp(s1->urlPrefix, s2->urlPrefix)) == 0) {
if (s1->len < s2->len) {
return 1;
} else if (s1->len > s2->len) {
return -1;
}
}
return -rc;
}
/******************************************************************************/
/*
* Publish a new web directory (Use the default URL handler)
*/
int websPublish(char_t *urlPrefix, char_t *path)
{
return websUrlHandlerDefine(urlPrefix, path, 0, websPublishHandler, 0);
}
/******************************************************************************/
/*
* Return the directory for a given prefix. Ignore empty prefixes
*/
char_t *websGetPublishDir(char_t *path, char_t **urlPrefix)
{
websUrlHandlerType *sp;
int i;
for (i = 0; i < websUrlHandlerMax; i++) {
sp = &websUrlHandler[i];
if (sp->urlPrefix[0] == '\0') {
continue;
}
if (sp->handler && gstrncmp(sp->urlPrefix, path, sp->len) == 0) {
if (urlPrefix) {
*urlPrefix = sp->urlPrefix;
}
return sp->webDir;
}
}
return NULL;
}
/******************************************************************************/
/*
* Publish URL handler. We just patch the web page Directory and let the
* default handler do the rest.
*/
static int websPublishHandler(webs_t wp, char_t *urlPrefix, char_t *webDir,
int sid, char_t *url, char_t *path, char_t *query)
{
int len;
a_assert(websValid(wp));
a_assert(path);
/*
* Trim the urlPrefix off the path and set the webdirectory. Add one to step
* over the trailing '/'
*/
len = gstrlen(urlPrefix) + 1;
websSetRequestPath(wp, webDir, &path[len]);
return 0;
}
/******************************************************************************/
/*
* See if any valid handlers are defined for this request. If so, call them
* and continue calling valid handlers until one accepts the request.
* Return true if a handler was invoked, else return FALSE.
*/
int websUrlHandlerRequest(webs_t wp)
{
websUrlHandlerType *sp;
int i, first;
a_assert(websValid(wp));
/*
* Delete the socket handler as we don't want to start reading any
* data on the connection as it may be for the next pipelined HTTP/1.1
* request if using Keep Alive
*/
socketDeleteHandler(wp->sid);
wp->state = WEBS_PROCESSING;
websStats.handlerHits++;
websSetRequestPath(wp, websGetDefaultDir(), NULL);
/*
* Eliminate security hole
*/
websCondenseMultipleChars(wp->path, '/');
websCondenseMultipleChars(wp->url, '/');
/*
* We loop over each handler in order till one accepts the request.
* The security handler will handle the request if access is NOT allowed.
*/
first = 1;
for (i = 0; i < websUrlHandlerMax; i++) {
sp = &websUrlHandler[i];
if (sp->handler && gstrncmp(sp->urlPrefix, wp->path, sp->len) == 0) {
if (first) {
websSetEnv(wp);
first = 0;
}
if ((*sp->handler)(wp, sp->urlPrefix, sp->webDir, sp->arg,
wp->url, wp->path, wp->query)) {
return 1;
}
if (!websValid(wp)) {
trace(0,
T("webs: handler %s called websDone, but didn't return 1\n"),
sp->urlPrefix);
return 1;
}
}
}
/*
* If no handler processed the request, then return an error. Note: It is
* the handlers responsibility to call websDone
*/
if (i >= websUrlHandlerMax) {
websError(wp, 200, T("No handler for this URL %s"), wp->url);
}
return 0;
}
#ifdef OBSOLETE_CODE
/******************************************************************************/
/*
* Tidy up the URL path. Return -1 if the URL is bad.
* Used to eliminate repeated directory delimiters ('/').
*/
static int websTidyUrl(webs_t wp)
{
char_t *parts[64]; /* Array of ptr's to URL parts */
char_t *token, *url, *tidyurl;
int i, len, npart;
a_assert(websValid(wp));
/*
* Copy the string so we don't destroy the original (yet)
*/
url = bstrdup(B_L, wp->url);
websDecodeUrl(url, url, gstrlen(url));
len = npart = 0;
parts[0] = NULL;
token = gstrtok(url, T("/"));
/*
* Look at each directory segment and process "." and ".." segments
* Don't allow the browser to pop outside the root web.
*/
while (token != NULL) {
if (gstrcmp(token, T("..")) == 0) {
if (npart > 0) {
npart--;
}
} else if (gstrcmp(token, T(".")) != 0) {
parts[npart] = token;
len += gstrlen(token) + 1;
npart++;
}
token = gstrtok(NULL, T("/"));
}
/*
* Re-construct URL. Need extra space all "/" and null.
*/
if (npart || (gstrcmp(url, T("/")) == 0) || (url[0] == '\0')) {
tidyurl = balloc(B_L, (len + 2) * sizeof(char_t));
*tidyurl = '\0';
for (i = 0; i < npart; i++) {
gstrcat(tidyurl, T("/"));
gstrcat(tidyurl, parts[i]);
}
bfree(B_L, url);
bfree(B_L, wp->url);
wp->url = tidyurl;
return 0;
} else {
bfree(B_L, url);
return -1;
}
}
#endif
/******************************************************************************/
/*
* Convert multiple adjacent occurrences of a given character to a single
* instance.
*/
static char_t *websCondenseMultipleChars(char_t *strToCondense, char_t cCondense)
{
if (strToCondense != NULL) {
char_t *pStr, *pScan;
pStr = pScan = strToCondense;
while (*pScan && *pStr) {
/*
* Advance scan pointer over multiple occurences of condense character
*/
while ((*pScan == cCondense) && (*(pScan + 1) == cCondense)) {
pScan++;
}
/*
* Copy character if an advance of the scan pointer has occurred
*/
if (pStr != pScan) {
*pStr = *pScan;
}
pScan++;
pStr++;
}
/*
* Zero terminate string if multiple adjacent characters were found and condensed
*/
if (pStr != pScan) {
*pStr = 0;
}
}
return strToCondense;
}
/******************************************************************************/

View File

@@ -1,282 +0,0 @@
License Agreement
THIS LICENSE ALLOWS ONLY THE LIMITED USE OF GO AHEAD SOFTWARE,
INC. PROPRIETARY CODE. PLEASE CAREFULLY READ THIS AGREEMENT AS IT
PERTAINS TO THIS LICENSE, YOU CERTIFY THAT YOU WILL USE THE SOFTWARE
ONLY IN THE MANNER PERMITTED HEREIN.
1. Definitions.
1.1 "Documentation" means any documentation GoAhead includes with the
Original Code.
1.2 "GoAhead" means Go Ahead Software, Inc.
1.3 "Intellectual Property Rights" means all rights, whether now existing
or hereinafter acquired, in and to trade secrets, patents, copyrights,
trademarks, know-how, as well as moral rights and similar rights of any
type under the laws of any governmental authority, domestic or foreign,
including rights in and to all applications and registrations relating
to any of the foregoing.
1.4 "License" or "Agreement" means this document.
1.5 "Modifications" means any addition to or deletion from the substance
or structure of either the Original Code or any previous Modifications.
1.6 "Original Code" means the Source Code to GoAhead<61>s proprietary
computer software entitled GoAhead WebServer.
1.7 "Response Header" means the first portion of the response message
output by the GoAhead WebServer, containing but not limited to, header
fields for date, content-type, server identification and cache control.
1.8 "Server Identification Field" means the field in the Response Header
which contains the text "Server: GoAhead-Webs".
1.9 "You" means an individual or a legal entity exercising rights under,
and complying with all of the terms of, this license or a future version
of this license. For legal entities, "You" includes any entity which
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct or
indirect, to cause the direction or management of such entity, whether
by contract or otherwise, or (b) ownership of fifty percent (50%) or
more of the outstanding shares or beneficial ownership of such entity.
2. Source Code License.
2.1 Limited Source Code Grant.
GoAhead hereby grants You a world-wide, royalty-free, non-exclusive
license, subject to third party intellectual property claims, to use,
reproduce, modify, copy and distribute the Original Code.
2.2 Binary Code.
GoAhead hereby grants You a world-wide, royalty-free, non-exclusive
license to copy and distribute the binary code versions of the Original
Code together with Your Modifications.
2.3 License Back to GoAhead.
You hereby grant in both source code and binary code to GoAhead a
world-wide, royalty-free, non-exclusive license to copy, modify, display,
use and sublicense any Modifications You make that are distributed or
planned for distribution. Within 30 days of either such event, You
agree to ship to GoAhead a file containing the Modifications (in a media
to be determined by the parties), including any programmers<72> notes and
other programmers<72> materials. Additionally, You will provide to GoAhead
a complete description of the product, the product code or model number,
the date on which the product is initially shipped, and a contact name,
phone number and e-mail address for future correspondence. GoAhead will
keep confidential all data specifically marked as such.
2.4 Restrictions on Use.
You may sublicense Modifications to third parties such as subcontractors
or OEM's provided that You enter into license agreements with such third
parties that bind such third parties to all the obligations under this
Agreement applicable to you and that are otherwise substantially similar
in scope and application to this Agreement.
3. Term.
This Agreement and license are effective from the time You accept the
terms of this Agreement until this Agreement is terminated. You may
terminate this Agreement at any time by uninstalling or destroying
all copies of the Original Code including any and all binary versions
and removing any Modifications to the Original Code existing in any
products. This Agreement will terminate immediately and without further
notice if You fail to comply with any provision of this Agreement. All
restrictions on use, and all other provisions that may reasonably
be interpreted to survive termination of this Agreement, will survive
termination of this Agreement for any reason. Upon termination, You agree
to uninstall or destroy all copies of the Original Code, Modifications,
and Documentation.
4. Trademarks and Brand.
4.1 License and Use.
GoAhead hereby grants to You a limited world-wide, royalty-free,
non-exclusive license to use the GoAhead trade names, trademarks, logos,
service marks and product designations posted in Exhibit A (collectively,
the "GoAhead Marks") in connection with the activities by You under this
Agreement. Additionally, GoAhead grants You a license under the terms
above to such GoAhead trademarks as shall be identified at a URL (the
"URL") provided by GoAhead. The use by You of GoAhead Marks shall be in
accordance with GoAhead<61>s trademark policies regarding trademark usage
as established at the web site designated by the URL, or as otherwise
communicated to You by GoAhead at its sole discretion. You understand and
agree that any use of GoAhead Marks in connection with this Agreement
shall not create any right, title or interest in or to such GoAhead
Marks and that all such use and goodwill associated with GoAhead Marks
will inure to the benefit of GoAhead.
4.2 Promotion by You of GoAhead WebServer Mark.
In consideration for the licenses granted by GoAhead to You herein, You
agree to notify GoAhead when You incorporate the GoAhead WebServer in
Your product and to inform GoAhead when such product begins to ship. You
agree to promote the Original Code by prominently and visibly displaying
a graphic of the GoAhead WebServer mark on the initial web page of Your
product that is displayed each time a user connects to it. You also agree
that GoAhead may identify your company as a user of the GoAhead WebServer
in conjunction with its own marketing efforts. You may further promote
the Original Code by displaying the GoAhead WebServer mark in marketing
and promotional materials such as the home page of your web site or web
pages promoting the product.
4.3 Placement of Copyright Notice by You.
You agree to include copies of the following notice (the "Notice")
regarding proprietary rights in all copies of the products that You
distribute, as follows: (i) embedded in the object code; and (ii) on
the title pages of all documentation. Furthermore, You agree to use
commercially reasonable efforts to cause any licensees of your products
to embed the Notice in object code and on the title pages or relevant
documentation. The Notice is as follows: Copyright (c) 20xx GoAhead
Software, Inc. All Rights Reserved. Unless GoAhead otherwise instructs,
the year 20xx is to be replaced with the year during which the release of
the Original Code containing the notice is issued by GoAhead. If this year
is not supplied with Documentation, GoAhead will supply it upon request.
4.4 No Modifications to Server Identification Field.
You agree not to remove or modify the Server identification Field
contained in the Response Header as defined in Section 1.6 and 1.7.
5. Warranty Disclaimers.
THE ORIGINAL CODE, THE DOCUMENTATION AND THE MEDIA UPON WHICH THE ORIGINAL
CODE IS RECORDED (IF ANY) ARE PROVIDED "AS IS" AND WITHOUT WARRANTIES OF
ANY KIND, EXPRESS, STATUTORY OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.
The entire risk as to the quality and performance of the Original Code
(including any Modifications You make) and the Documentation is with
You. Should the Original Code or the Documentation prove defective,
You (and not GoAhead or its distributors, licensors or dealers) assume
the entire cost of all necessary servicing or repair. GoAhead does not
warrant that the functions contained in the Original Code will meet your
requirements or operate in the combination that You may select for use,
that the operation of the Original Code will be uninterrupted or error
free, or that defects in the Original Code will be corrected. No oral
or written statement by GoAhead or by a representative of GoAhead shall
create a warranty or increase the scope of this warranty.
GOAHEAD DOES NOT WARRANT THE ORIGINAL CODE AGAINST INFRINGEMENT OR THE
LIKE WITH RESPECT TO ANY COPYRIGHT, PATENT, TRADE SECRET, TRADEMARK
OR OTHER PROPRIETARY RIGHT OF ANY THIRD PARTY AND DOES NOT WARRANT
THAT THE ORIGINAL CODE DOES NOT INCLUDE ANY VIRUS, SOFTWARE ROUTINE
OR OTHER SOFTWARE DESIGNED TO PERMIT UNAUTHORIZED ACCESS, TO DISABLE,
ERASE OR OTHERWISE HARM SOFTWARE, HARDWARE OR DATA, OR TO PERFORM ANY
OTHER SUCH ACTIONS.
Any warranties that by law survive the foregoing disclaimers shall
terminate ninety (90) days from the date You received the Original Code.
6. Limitation of Liability.
YOUR SOLE REMEDIES AND GOAHEAD'S ENTIRE LIABILITY ARE SET FORTH ABOVE. IN
NO EVENT WILL GOAHEAD OR ITS DISTRIBUTORS OR DEALERS BE LIABLE FOR
DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES RESULTING FROM
THE USE OF THE ORIGINAL CODE, THE INABILITY TO USE THE ORIGINAL CODE,
OR ANY DEFECT IN THE ORIGINAL CODE, INCLUDING ANY LOST PROFITS, EVEN IF
THEY HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You agree that GoAhead and its distributors and dealers will not be
LIABLE for defense or indemnity with respect to any claim against You
by any third party arising from your possession or use of the Original
Code or the Documentation.
In no event will GoAhead<61>s total liability to You for all damages, losses,
and causes of action (whether in contract, tort, including negligence,
or otherwise) exceed the amount You paid for this product.
SOME STATES DO NOT ALLOW LIMITATIONS ON HOW LONG AN IMPLIED WARRANTY
LASTS, AND SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION
OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THE ABOVE LIMITATIONS OR
EXCLUSIONS MAY NOT APPLY TO YOU. THIS WARRANTY GIVES YOU SPECIFIC LEGAL
RIGHTS AND YOU MAY ALSO HAVE OTHER RIGHTS WHICH VARY FROM STATE TO STATE.
7. Indemnification by You.
You agree to indemnify and hold GoAhead harmless against any and all
claims, losses, damages and costs (including legal expenses and reasonable
counsel fees) arising out of any claim of a third party with respect to
the contents of the Your products, and any intellectual property rights
or other rights or interests related thereto.
8. High Risk Activities.
The Original Code is not fault-tolerant and is not designed , manufactured
or intended for use or resale as online control equipment in hazardous
environments requiring fail-safe performance, such as in the operation
of nuclear facilities, aircraft navigation or communication systems,
air traffic control, direct life support machines or weapons systems,
in which the failure of the Original Code could lead directly to death,
personal injury, or severe physical or environmental damage. GoAhead and
its suppliers specifically disclaim any express or implied warranty of
fitness for any high risk uses listed above.
9. Government Restricted Rights.
For units of the Department of Defense, use, duplication, or disclosure
by the Government is subject to restrictions as set forth in subparagraph
(c)(1)(ii) of the Rights in Technical Data and Computer Software clause
at DFARS 252.227-7013. Contractor/manufacturer is GoAhead Software,
Inc., 10900 N.E. 8th Street, Suite 750, Bellevue, Washington 98004.
If the Commercial Computer Software Restricted rights clause at FAR
52.227-19 or its successors apply, the Software and Documentation
constitute restricted computer software as defined in that clause and
the Government shall not have the license for published software set
forth in subparagraph (c)(3) of that clause.
The Original Code (i) was developed at private expense, and no part of it
was developed with governmental funds; (ii) is a trade secret of GoAhead
(or its licensor(s)) for all purposes of the Freedom of Information Act;
(iii) is "restricted computer software" subject to limited utilization as
provided in the contract between the vendor and the governmental entity;
and (iv) in all respects is proprietary data belonging solely to GoAhead
(or its licensor(s)).
10. Governing Law and Interpretation.
This Agreement shall be interpreted under and governed by the laws of the
State of Washington, without regard to its rules governing the conflict of
laws. If any provision of this Agreement is held illegal or unenforceable
by a court or tribunal of competent jurisdiction, the remaining provisions
of this Agreement shall remain in effect and the invalid provision deemed
modified to the least degree necessary to remedy such invalidity.
11. Entire Agreement.
This Agreement is the complete agreement between GoAhead and You and
supersedes all prior agreements, oral or written, with respect to the
subject matter hereof.
If You have any questions concerning this Agreement, You may write to
GoAhead Software, Inc., 10900 N.E. 8th Street, Suite 750, Bellevue,
Washington 98004 or send e-mail to info@goahead.com.
BY CLICKING ON THE "Register" BUTTON ON THE REGISTRATION FORM, YOU
ACCEPT AND AGREE TO BE BOUND BY ALL OF THE TERMS AND CONDITIONS SET
FORTH IN THIS AGREEMENT. IF YOU DO NOT WISH TO ACCEPT THIS LICENSE OR
YOU DO NOT QUALIFY FOR A LICENSE BASED ON THE TERMS SET FORTH ABOVE,
YOU MUST NOT CLICK THE "Register" BUTTON.
Exhibit A
GoAhead Trademarks, Logos, and Product Designation Information
01/28/00

View File

@@ -1,50 +0,0 @@
/* MD5.H - header file for MD5C.C
*
* $Id$
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
#ifndef _h_MD5
#define _h_MD5 1
#ifndef UINT4
#define UINT4 unsigned long
#endif
#ifndef POINTER
#define POINTER unsigned char *
#endif
/* MD5 context. */
typedef struct {
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD5_CONTEXT;
extern void MD5Init (MD5_CONTEXT *);
extern void MD5Update (MD5_CONTEXT *, unsigned char *, unsigned int);
extern void MD5Final (unsigned char [16], MD5_CONTEXT *);
#endif /* _h_MD5 */

View File

@@ -1,337 +0,0 @@
/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
*
* $Id$
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
#include "md5.h"
/* Constants for MD5Transform routine.
*/
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
static void MD5Transform (UINT4 [4], unsigned char [64]);
static void Encode (unsigned char *, UINT4 *, unsigned int);
static void Decode (UINT4 *, unsigned char *, unsigned int);
static void MD5_memcpy (POINTER, POINTER, unsigned int);
static void MD5_memset (POINTER, int, unsigned int);
static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/*
* Note: The following MD5 macros can be implemented as functions
* for code compactness, (at the expense of execution speed).
*/
/* F, G, H and I are basic MD5 functions.
*/
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
/* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
void MD5Init (context)
MD5_CONTEXT *context; /* context */
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.
*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/* MD5 block update operation. Continues an MD5 message-digest
operation, processing another message block, and updating the
context.
*/
void MD5Update (context, input, inputLen)
MD5_CONTEXT *context; /* context */
unsigned char *input; /* input block */
unsigned int inputLen; /* length of input block */
{
unsigned int i, index, partLen;
/* Compute number of bytes mod 64 */
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += ((UINT4)inputLen << 3))
< ((UINT4)inputLen << 3))
context->count[1]++;
context->count[1] += ((UINT4)inputLen >> 29);
partLen = 64 - index;
/* Transform as many times as possible.
*/
if (inputLen >= partLen) {
MD5_memcpy
((POINTER)&context->buffer[index], (POINTER)input, partLen);
MD5Transform (context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform (context->state, &input[i]);
index = 0;
}
else
i = 0;
/* Buffer remaining input */
MD5_memcpy
((POINTER)&context->buffer[index], (POINTER)&input[i],
inputLen-i);
}
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
the message digest and zeroizing the context.
*/
void MD5Final (digest, context)
unsigned char digest[16]; /* message digest */
MD5_CONTEXT *context; /* context */
{
unsigned char bits[8];
unsigned int index, padLen;
/* Save number of bits */
Encode (bits, context->count, 8);
/* Pad out to 56 mod 64.
*/
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5Update (context, PADDING, padLen);
/* Append length (before padding) */
MD5Update (context, bits, 8);
/* Store state in digest */
Encode (digest, context->state, 16);
/* Zeroize sensitive information.
*/
MD5_memset ((POINTER)context, 0, sizeof (*context));
}
/* MD5 basic transformation. Transforms state based on block.
*/
static void MD5Transform (state, block)
UINT4 state[4];
unsigned char block[64];
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode (x, block, 64);
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/* Zeroize sensitive information.
*/
MD5_memset ((POINTER)x, 0, sizeof (x));
}
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
a multiple of 4.
*/
static void Encode (output, input, len)
unsigned char *output;
UINT4 *input;
unsigned int len;
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
/* Decodes input (unsigned char) into output (UINT4). Assumes len is
a multiple of 4.
*/
static void Decode (output, input, len)
UINT4 *output;
unsigned char *input;
unsigned int len;
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
}
/* Note: Replace "for loop" with standard memcpy if possible.
*/
static void MD5_memcpy (output, input, len)
POINTER output;
POINTER input;
unsigned int len;
{
unsigned int i;
for (i = 0; i < len; i++)
output[i] = input[i];
}
/* Note: Replace "for loop" with standard memset if possible.
*/
static void MD5_memset (output, value, len)
POINTER output;
int value;
unsigned int len;
{
unsigned int i;
for (i = 0; i < len; i++)
((char *)output)[i] = (char)value;
}

View File

@@ -1,116 +0,0 @@
/*
* mime.c -- Web server mime types
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* Mime types and file extensions. This module maps URL extensions to
* content types.
*/
/********************************* Includes ***********************************/
#include "wsIntrn.h"
/******************************** Global Data *********************************/
/*
* Addd entries to the MimeList as required for your content
*/
websMimeType websMimeList[] = {
{ T("application/java"), T(".class") },
{ T("application/java"), T(".jar") },
{ T("text/html"), T(".asp") },
{ T("text/html"), T(".htm") },
{ T("text/html"), T(".html") },
{ T("image/gif"), T(".gif") },
{ T("image/jpeg"), T(".jpg") },
{ T("text/css"), T(".css") },
{ T("text/plain"), T(".txt") },
{ T("application/x-javascript"), T(".js") },
#ifdef MORE_MIME_TYPES
{ T("application/binary"), T(".exe") },
{ T("application/compress"), T(".z") },
{ T("application/gzip"), T(".gz") },
{ T("application/octet-stream"), T(".bin") },
{ T("application/oda"), T(".oda") },
{ T("application/pdf"), T(".pdf") },
{ T("application/postscript"), T(".ai") },
{ T("application/postscript"), T(".eps") },
{ T("application/postscript"), T(".ps") },
{ T("application/rtf"), T(".rtf") },
{ T("application/x-bcpio"), T(".bcpio") },
{ T("application/x-cpio"), T(".cpio") },
{ T("application/x-csh"), T(".csh") },
{ T("application/x-dvi"), T(".dvi") },
{ T("application/x-gtar"), T(".gtar") },
{ T("application/x-hdf"), T(".hdf") },
{ T("application/x-latex"), T(".latex") },
{ T("application/x-mif"), T(".mif") },
{ T("application/x-netcdf"), T(".nc") },
{ T("application/x-netcdf"), T(".cdf") },
{ T("application/x-ns-proxy-autoconfig"), T(".pac") },
{ T("application/x-patch"), T(".patch") },
{ T("application/x-sh"), T(".sh") },
{ T("application/x-shar"), T(".shar") },
{ T("application/x-sv4cpio"), T(".sv4cpio") },
{ T("application/x-sv4crc"), T(".sv4crc") },
{ T("application/x-tar"), T(".tar") },
{ T("application/x-tcl"), T(".tcl") },
{ T("application/x-tex"), T(".tex") },
{ T("application/x-texinfo"), T(".texinfo") },
{ T("application/x-texinfo"), T(".texi") },
{ T("application/x-troff"), T(".t") },
{ T("application/x-troff"), T(".tr") },
{ T("application/x-troff"), T(".roff") },
{ T("application/x-troff-man"), T(".man") },
{ T("application/x-troff-me"), T(".me") },
{ T("application/x-troff-ms"), T(".ms") },
{ T("application/x-ustar"), T(".ustar") },
{ T("application/x-wais-source"), T(".src") },
{ T("application/zip"), T(".zip") },
{ T("audio/basic"), T(".au snd") },
{ T("audio/x-aiff"), T(".aif") },
{ T("audio/x-aiff"), T(".aiff") },
{ T("audio/x-aiff"), T(".aifc") },
{ T("audio/x-wav"), T(".wav") },
{ T("audio/x-wav"), T(".ram") },
{ T("image/ief"), T(".ief") },
{ T("image/jpeg"), T(".jpeg") },
{ T("image/jpeg"), T(".jpe") },
{ T("image/tiff"), T(".tiff") },
{ T("image/tiff"), T(".tif") },
{ T("image/x-cmu-raster"), T(".ras") },
{ T("image/x-portable-anymap"), T(".pnm") },
{ T("image/x-portable-bitmap"), T(".pbm") },
{ T("image/x-portable-graymap"), T(".pgm") },
{ T("image/x-portable-pixmap"), T(".ppm") },
{ T("image/x-rgb"), T(".rgb") },
{ T("image/x-xbitmap"), T(".xbm") },
{ T("image/x-xpixmap"), T(".xpm") },
{ T("image/x-xwindowdump"), T(".xwd") },
{ T("text/html"), T(".cfm") },
{ T("text/html"), T(".shtm") },
{ T("text/html"), T(".shtml") },
{ T("text/richtext"), T(".rtx") },
{ T("text/tab-separated-values"), T(".tsv") },
{ T("text/x-setext"), T(".etx") },
{ T("video/mpeg"), T(".mpeg mpg mpe") },
{ T("video/quicktime"), T(".qt") },
{ T("video/quicktime"), T(".mov") },
{ T("video/x-msvideo"), T(".avi") },
{ T("video/x-sgi-movie"), T(".movie") },
#endif
{ NULL, NULL},
};
/*****************************************************************************/

View File

@@ -1,675 +0,0 @@
/*
* misc.c -- Miscellaneous routines.
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/********************************* Includes ***********************************/
#ifdef UEMF
#include "uemf.h"
#else
#include "basic/basicInternal.h"
#endif
/********************************* Defines ************************************/
/*
* Sprintf buffer structure. Make the increment 64 so that
* a balloc can use a 64 byte block.
*/
#define STR_REALLOC 0x1 /* Reallocate the buffer as required */
#define STR_INC 64 /* Growth increment */
typedef struct {
char_t *s; /* Pointer to buffer */
int size; /* Current buffer size */
int max; /* Maximum buffer size */
int count; /* Buffer count */
int flags; /* Allocation flags */
} strbuf_t;
/*
* Sprintf formatting flags
*/
enum flag {
flag_none = 0,
flag_minus = 1,
flag_plus = 2,
flag_space = 4,
flag_hash = 8,
flag_zero = 16,
flag_short = 32,
flag_long = 64
};
/************************** Forward Declarations ******************************/
static int dsnprintf(char_t **s, int size, char_t *fmt, va_list arg,
int msize);
#if !defined(__rtems__)
static int strnlen(char_t *s, unsigned int n);
#endif
static void put_char(strbuf_t *buf, char_t c);
static void put_string(strbuf_t *buf, char_t *s, int len,
int width, int prec, enum flag f);
static void put_ulong(strbuf_t *buf, unsigned long int value, int base,
int upper, char_t *prefix, int width, int prec, enum flag f);
/************************************ Code ************************************/
/*
* "basename" returns a pointer to the last component of a pathname
* LINUX, LynxOS and Mac OS X have their own basename function
*/
#if (!defined (LINUX) && !defined (LYNX) && !defined (MACOSX))
char_t *basename(char_t *name)
{
char_t *cp;
#if (defined (NW) || defined (WIN))
if (((cp = gstrrchr(name, '\\')) == NULL) &&
((cp = gstrrchr(name, '/')) == NULL)) {
return name;
#else
if ((cp = gstrrchr(name, '/')) == NULL) {
return name;
#endif
} else if (*(cp + 1) == '\0' && cp == name) {
return name;
} else if (*(cp + 1) == '\0' && cp != name) {
return T("");
} else {
return ++cp;
}
}
#endif /* ! LINUX & ! LYNX & ! MACOSX */
/******************************************************************************/
/*
* Returns a pointer to the directory component of a pathname. bufsize is
* the size of the buffer in BYTES!
*/
char_t *dirname(char_t *buf, char_t *name, int bufsize)
{
char_t *cp;
int len;
a_assert(name);
a_assert(buf);
a_assert(bufsize > 0);
#if (defined (WIN) || defined (NW))
if ((cp = gstrrchr(name, '/')) == NULL &&
(cp = gstrrchr(name, '\\')) == NULL)
#else
if ((cp = gstrrchr(name, '/')) == NULL)
#endif
{
gstrcpy(buf, T("."));
return buf;
}
if ((*(cp + 1) == '\0' && cp == name)) {
gstrncpy(buf, T("."), TSZ(bufsize));
gstrcpy(buf, T("."));
return buf;
}
len = cp - name;
if (len < bufsize) {
gstrncpy(buf, name, len);
buf[len] = '\0';
} else {
gstrncpy(buf, name, TSZ(bufsize));
buf[bufsize - 1] = '\0';
}
return buf;
}
/******************************************************************************/
/*
* sprintf and vsprintf are bad, ok. You can easily clobber memory. Use
* fmtAlloc and fmtValloc instead! These functions do _not_ support floating
* point, like %e, %f, %g...
*/
int fmtAlloc(char_t **s, int n, char_t *fmt, ...)
{
va_list ap;
int result;
a_assert(s);
a_assert(fmt);
*s = NULL;
va_start(ap, fmt);
result = dsnprintf(s, n, fmt, ap, 0);
va_end(ap);
return result;
}
/******************************************************************************/
/*
* Support a static buffer version for small buffers only!
*/
int fmtStatic(char_t *s, int n, char_t *fmt, ...)
{
va_list ap;
int result;
a_assert(s);
a_assert(fmt);
a_assert(n <= 256);
if (n <= 0) {
return -1;
}
va_start(ap, fmt);
result = dsnprintf(&s, n, fmt, ap, 0);
va_end(ap);
return result;
}
/******************************************************************************/
/*
* This function appends the formatted string to the supplied string,
* reallocing if required.
*/
int fmtRealloc(char_t **s, int n, int msize, char_t *fmt, ...)
{
va_list ap;
int result;
a_assert(s);
a_assert(fmt);
if (msize == -1) {
*s = NULL;
}
va_start(ap, fmt);
result = dsnprintf(s, n, fmt, ap, msize);
va_end(ap);
return result;
}
/******************************************************************************/
/*
* A vsprintf replacement.
*/
int fmtValloc(char_t **s, int n, char_t *fmt, va_list arg)
{
a_assert(s);
a_assert(fmt);
*s = NULL;
return dsnprintf(s, n, fmt, arg, 0);
}
/******************************************************************************/
/*
* Dynamic sprintf implementation. Supports dynamic buffer allocation.
* This function can be called multiple times to grow an existing allocated
* buffer. In this case, msize is set to the size of the previously allocated
* buffer. The buffer will be realloced, as required. If msize is set, we
* return the size of the allocated buffer for use with the next call. For
* the first call, msize can be set to -1.
*/
static int dsnprintf(char_t **s, int size, char_t *fmt, va_list arg, int msize)
{
strbuf_t buf;
char_t c;
a_assert(s);
a_assert(fmt);
memset(&buf, 0, sizeof(buf));
buf.s = *s;
if (*s == NULL || msize != 0) {
buf.max = size;
buf.flags |= STR_REALLOC;
if (msize != 0) {
buf.size = max(msize, 0);
}
if (*s != NULL && msize != 0) {
buf.count = gstrlen(*s);
}
} else {
buf.size = size;
}
while ((c = *fmt++) != '\0') {
if (c != '%' || (c = *fmt++) == '%') {
put_char(&buf, c);
} else {
enum flag f = flag_none;
int width = 0;
int prec = -1;
for ( ; c != '\0'; c = *fmt++) {
if (c == '-') {
f |= flag_minus;
} else if (c == '+') {
f |= flag_plus;
} else if (c == ' ') {
f |= flag_space;
} else if (c == '#') {
f |= flag_hash;
} else if (c == '0') {
f |= flag_zero;
} else {
break;
}
}
if (c == '*') {
width = va_arg(arg, int);
if (width < 0) {
f |= flag_minus;
width = -width;
}
c = *fmt++;
} else {
for ( ; gisdigit((int)c); c = *fmt++) {
width = width * 10 + (c - '0');
}
}
if (c == '.') {
f &= ~flag_zero;
c = *fmt++;
if (c == '*') {
prec = va_arg(arg, int);
c = *fmt++;
} else {
for (prec = 0; gisdigit((int)c); c = *fmt++) {
prec = prec * 10 + (c - '0');
}
}
}
if (c == 'h' || c == 'l') {
f |= (c == 'h' ? flag_short : flag_long);
c = *fmt++;
}
if (c == 'd' || c == 'i') {
long int value;
if (f & flag_short) {
value = (short int) va_arg(arg, int);
} else if (f & flag_long) {
value = va_arg(arg, long int);
} else {
value = va_arg(arg, int);
}
if (value >= 0) {
if (f & flag_plus) {
put_ulong(&buf, value, 10, 0, T("+"), width, prec, f);
} else if (f & flag_space) {
put_ulong(&buf, value, 10, 0, T(" "), width, prec, f);
} else {
put_ulong(&buf, value, 10, 0, NULL, width, prec, f);
}
} else {
put_ulong(&buf, -value, 10, 0, T("-"), width, prec, f);
}
} else if (c == 'o' || c == 'u' || c == 'x' || c == 'X') {
unsigned long int value;
if (f & flag_short) {
value = (unsigned short int) va_arg(arg, unsigned int);
} else if (f & flag_long) {
value = va_arg(arg, unsigned long int);
} else {
value = va_arg(arg, unsigned int);
}
if (c == 'o') {
if (f & flag_hash && value != 0) {
put_ulong(&buf, value, 8, 0, T("0"), width, prec, f);
} else {
put_ulong(&buf, value, 8, 0, NULL, width, prec, f);
}
} else if (c == 'u') {
put_ulong(&buf, value, 10, 0, NULL, width, prec, f);
} else {
if (f & flag_hash && value != 0) {
if (c == 'x') {
put_ulong(&buf, value, 16, 0, T("0x"), width,
prec, f);
} else {
put_ulong(&buf, value, 16, 1, T("0X"), width,
prec, f);
}
} else {
/* 04 Apr 02 BgP -- changed so that %X correctly outputs
* uppercase hex digits when requested.
put_ulong(&buf, value, 16, 0, NULL, width, prec, f);
*/
put_ulong(&buf, value, 16, ('X' == c) , NULL, width, prec, f);
}
}
} else if (c == 'c') {
char_t value = va_arg(arg, int);
put_char(&buf, value);
} else if (c == 's' || c == 'S') {
char_t *value = va_arg(arg, char_t *);
if (value == NULL) {
put_string(&buf, T("(null)"), -1, width, prec, f);
} else if (f & flag_hash) {
put_string(&buf,
value + 1, (char_t) *value, width, prec, f);
} else {
put_string(&buf, value, -1, width, prec, f);
}
} else if (c == 'p') {
void *value = va_arg(arg, void *);
put_ulong(&buf,
(unsigned long int) value, 16, 0, T("0x"), width, prec, f);
} else if (c == 'n') {
if (f & flag_short) {
short int *value = va_arg(arg, short int *);
*value = buf.count;
} else if (f & flag_long) {
long int *value = va_arg(arg, long int *);
*value = buf.count;
} else {
int *value = va_arg(arg, int *);
*value = buf.count;
}
} else {
put_char(&buf, c);
}
}
}
if (buf.s == NULL) {
put_char(&buf, '\0');
}
/*
* If the user requested a dynamic buffer (*s == NULL), ensure it is returned.
*/
if (*s == NULL || msize != 0) {
*s = buf.s;
}
if (*s != NULL && size > 0) {
if (buf.count < size) {
(*s)[buf.count] = '\0';
} else {
(*s)[buf.size - 1] = '\0';
}
}
if (msize != 0) {
return buf.size;
}
return buf.count;
}
/******************************************************************************/
/*
* Return the length of a string limited by a given length
*/
#if !defined(__rtems__)
static int strnlen(char_t *s, unsigned int n)
{
unsigned int len;
len = gstrlen(s);
return min(len, n);
}
#endif
/******************************************************************************/
/*
* Add a character to a string buffer
*/
static void put_char(strbuf_t *buf, char_t c)
{
if (buf->count >= (buf->size - 1)) {
if (! (buf->flags & STR_REALLOC)) {
return;
}
buf->size += STR_INC;
if (buf->size > buf->max && buf->size > STR_INC) {
/*
* Caller should increase the size of the calling buffer
*/
buf->size -= STR_INC;
return;
}
if (buf->s == NULL) {
buf->s = balloc(B_L, buf->size * sizeof(char_t));
} else {
buf->s = brealloc(B_L, buf->s, buf->size * sizeof(char_t));
}
}
buf->s[buf->count] = c;
if (c != '\0') {
++buf->count;
}
}
/******************************************************************************/
/*
* Add a string to a string buffer
*/
static void put_string(strbuf_t *buf, char_t *s, int len, int width,
int prec, enum flag f)
{
int i;
if (len < 0) {
len = strnlen(s, prec >= 0 ? prec : ULONG_MAX);
} else if (prec >= 0 && prec < len) {
len = prec;
}
if (width > len && !(f & flag_minus)) {
for (i = len; i < width; ++i) {
put_char(buf, ' ');
}
}
for (i = 0; i < len; ++i) {
put_char(buf, s[i]);
}
if (width > len && f & flag_minus) {
for (i = len; i < width; ++i) {
put_char(buf, ' ');
}
}
}
/******************************************************************************/
/*
* Add a long to a string buffer
*/
static void put_ulong(strbuf_t *buf, unsigned long int value, int base,
int upper, char_t *prefix, int width, int prec, enum flag f)
{
unsigned long x, x2;
int len, zeros, i;
for (len = 1, x = 1; x < ULONG_MAX / base; ++len, x = x2) {
x2 = x * base;
if (x2 > value) {
break;
}
}
zeros = (prec > len) ? prec - len : 0;
width -= zeros + len;
if (prefix != NULL) {
width -= strnlen(prefix, ULONG_MAX);
}
if (!(f & flag_minus)) {
if (f & flag_zero) {
for (i = 0; i < width; ++i) {
put_char(buf, '0');
}
} else {
for (i = 0; i < width; ++i) {
put_char(buf, ' ');
}
}
}
if (prefix != NULL) {
put_string(buf, prefix, -1, 0, -1, flag_none);
}
for (i = 0; i < zeros; ++i) {
put_char(buf, '0');
}
for ( ; x > 0; x /= base) {
int digit = (value / x) % base;
put_char(buf, (char) ((digit < 10 ? '0' : (upper ? 'A' : 'a') - 10) +
digit));
}
if (f & flag_minus) {
for (i = 0; i < width; ++i) {
put_char(buf, ' ');
}
}
}
/******************************************************************************/
/*
* Convert an ansi string to a unicode string. On an error, we return the
* original ansi string which is better than returning NULL. nBytes is the
* size of the destination buffer (ubuf) in _bytes_.
*/
char_t *ascToUni(char_t *ubuf, char *str, int nBytes)
{
#ifdef UNICODE
if (MultiByteToWideChar(CP_ACP, 0, str, nBytes / sizeof(char_t), ubuf,
nBytes / sizeof(char_t)) < 0) {
return (char_t*) str;
}
#else
strncpy(ubuf, str, nBytes);
#endif
return ubuf;
}
/******************************************************************************/
/*
* Convert a unicode string to an ansi string. On an error, return the
* original unicode string which is better than returning NULL.
* N.B. nBytes is the number of _bytes_ in the destination buffer, buf.
*/
char *uniToAsc(char *buf, char_t *ustr, int nBytes)
{
#ifdef UNICODE
if (WideCharToMultiByte(CP_ACP, 0, ustr, nBytes, buf, nBytes, NULL,
NULL) < 0) {
return (char*) ustr;
}
#else
strncpy(buf, ustr, nBytes);
#endif
return (char*) buf;
}
/******************************************************************************/
/*
* allocate (balloc) a buffer and do ascii to unicode conversion into it.
* cp points to the ascii buffer. alen is the length of the buffer to be
* converted not including a terminating NULL. Return a pointer to the
* unicode buffer which must be bfree'd later. Return NULL on failure to
* get buffer. The buffer returned is NULL terminated.
*/
char_t *ballocAscToUni(char *cp, int alen)
{
char_t *unip;
int ulen;
ulen = (alen + 1) * sizeof(char_t);
if ((unip = balloc(B_L, ulen)) == NULL) {
return NULL;
}
ascToUni(unip, cp, ulen);
unip[alen] = 0;
return unip;
}
/******************************************************************************/
/*
* allocate (balloc) a buffer and do unicode to ascii conversion into it.
* unip points to the unicoded string. ulen is the number of characters
* in the unicode string not including a teminating null. Return a pointer
* to the ascii buffer which must be bfree'd later. Return NULL on failure
* to get buffer. The buffer returned is NULL terminated.
*/
char *ballocUniToAsc(char_t *unip, int ulen)
{
char * cp;
if ((cp = balloc(B_L, ulen+1)) == NULL) {
return NULL;
}
uniToAsc(cp, unip, ulen);
cp[ulen] = '\0';
return cp;
}
/******************************************************************************/
/*
* convert a hex string to an integer. The end of the string or a non-hex
* character will indicate the end of the hex specification.
*/
unsigned int hextoi(char_t *hexstring)
{
register char_t *h;
register unsigned int c, v;
v = 0;
h = hexstring;
if (*h == '0' && (*(h+1) == 'x' || *(h+1) == 'X')) {
h += 2;
}
while ((c = (unsigned int)*h++) != 0) {
if (c >= '0' && c <= '9') {
c -= '0';
} else if (c >= 'a' && c <= 'f') {
c = (c - 'a') + 10;
} else if (c >= 'A' && c <= 'F') {
c = (c - 'A') + 10;
} else {
break;
}
v = (v * 0x10) + c;
}
return v;
}
/******************************************************************************/
/*
* convert a string to an integer. If the string starts with "0x" or "0X"
* a hexidecimal conversion is done.
*/
unsigned int gstrtoi(char_t *s)
{
if (*s == '0' && (*(s+1) == 'x' || *(s+1) == 'X')) {
s += 2;
return hextoi(s);
}
return gatoi(s);
}
/******************************************************************************/

View File

@@ -1,584 +0,0 @@
/*
* ringq.c -- Ring queue buffering module
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* A ring queue allows maximum utilization of memory for data storage and is
* ideal for input/output buffering. This module provides a highly efficient
* implementation and a vehicle for dynamic strings.
*
* WARNING: This is a public implementation and callers have full access to
* the queue structure and pointers. Change this module very carefully.
*
* This module follows the open/close model.
*
* Operation of a ringq where rq is a pointer to a ringq :
*
* rq->buflen contains the size of the buffer.
* rq->buf will point to the start of the buffer.
* rq->servp will point to the first (un-consumed) data byte.
* rq->endp will point to the next free location to which new data is added
* rq->endbuf will point to one past the end of the buffer.
*
* Eg. If the ringq contains the data "abcdef", it might look like :
*
* +-------------------------------------------------------------------+
* | | | | | | | | a | b | c | d | e | f | | | | |
* +-------------------------------------------------------------------+
* ^ ^ ^ ^
* | | | |
* rq->buf rq->servp rq->endp rq->enduf
*
* The queue is empty when servp == endp. This means that the queue will hold
* at most rq->buflen -1 bytes. It is the filler's responsibility to ensure
* the ringq is never filled such that servp == endp.
*
* It is the filler's responsibility to "wrap" the endp back to point to
* rq->buf when the pointer steps past the end. Correspondingly it is the
* consumers responsibility to "wrap" the servp when it steps to rq->endbuf.
* The ringqPutc and ringqGetc routines will do this automatically.
*/
/********************************* Includes ***********************************/
#ifdef UEMF
#include "uemf.h"
#else
#include "basic/basicInternal.h"
#endif
/*********************************** Defines **********************************/
/*
* Faster than a function call
*/
#define RINGQ_LEN(rq) \
((rq->servp > rq->endp) ? \
(rq->buflen + (rq->endp - rq->servp)) : \
(rq->endp - rq->servp))
/***************************** Forward Declarations ***************************/
static int ringqGrow(ringq_t *rq);
static int getBinBlockSize(int size);
int ringqGrowCalls = 0;
/*********************************** Code *************************************/
/*
* Create a new ringq. "increment" is the amount to increase the size of the
* ringq should it need to grow to accomodate data being added. "maxsize" is
* an upper limit (sanity level) beyond which the q must not grow. Set maxsize
* to -1 to imply no upper limit. The buffer for the ringq is always
* dynamically allocated. Set maxsize
*/
int ringqOpen(ringq_t *rq, int initSize, int maxsize)
{
int increment;
a_assert(rq);
a_assert(initSize >= 0);
increment = getBinBlockSize(initSize);
if ((rq->buf = balloc(B_L, (increment))) == NULL) {
return -1;
}
rq->maxsize = maxsize;
rq->buflen = increment;
rq->increment = increment;
rq->endbuf = &rq->buf[rq->buflen];
rq->servp = rq->buf;
rq->endp = rq->buf;
*rq->servp = '\0';
return 0;
}
/******************************************************************************/
/*
* Delete a ringq and free the ringq buffer.
*/
void ringqClose(ringq_t *rq)
{
a_assert(rq);
a_assert(rq->buflen == (rq->endbuf - rq->buf));
if (rq == NULL) {
return;
}
ringqFlush(rq);
bfree(B_L, (char*) rq->buf);
rq->buf = NULL;
}
/******************************************************************************/
/*
* Return the length of the data in the ringq. Users must fill the queue to
* a high water mark of at most one less than the queue size.
*/
int ringqLen(ringq_t *rq)
{
a_assert(rq);
a_assert(rq->buflen == (rq->endbuf - rq->buf));
if (rq->servp > rq->endp) {
return rq->buflen + rq->endp - rq->servp;
} else {
return rq->endp - rq->servp;
}
}
/******************************************************************************/
/*
* Get a byte from the queue
*/
int ringqGetc(ringq_t *rq)
{
char_t c;
char_t* cp;
a_assert(rq);
a_assert(rq->buflen == (rq->endbuf - rq->buf));
if (rq->servp == rq->endp) {
return -1;
}
cp = (char_t*) rq->servp;
c = *cp++;
rq->servp = (unsigned char *) cp;
if (rq->servp >= rq->endbuf) {
rq->servp = rq->buf;
}
return c;
}
/******************************************************************************/
/*
* Add a char to the queue. Note if being used to store wide strings
* this does not add a trailing '\0'. Grow the q as required.
*/
int ringqPutc(ringq_t *rq, char_t c)
{
char_t *cp;
a_assert(rq);
a_assert(rq->buflen == (rq->endbuf - rq->buf));
if ((ringqPutBlkMax(rq) < (int) sizeof(char_t)) && !ringqGrow(rq)) {
return -1;
}
cp = (char_t*) rq->endp;
*cp++ = (char_t) c;
rq->endp = (unsigned char *) cp;
if (rq->endp >= rq->endbuf) {
rq->endp = rq->buf;
}
return 0;
}
/******************************************************************************/
/*
* Insert a wide character at the front of the queue
*/
int ringqInsertc(ringq_t *rq, char_t c)
{
char_t *cp;
a_assert(rq);
a_assert(rq->buflen == (rq->endbuf - rq->buf));
if (ringqPutBlkMax(rq) < (int) sizeof(char_t) && !ringqGrow(rq)) {
return -1;
}
if (rq->servp <= rq->buf) {
rq->servp = rq->endbuf;
}
cp = (char_t*) rq->servp;
*--cp = (char_t) c;
rq->servp = (unsigned char *) cp;
return 0;
}
/******************************************************************************/
/*
* Add a string to the queue. Add a trailing null (maybe two nulls)
*/
int ringqPutStr(ringq_t *rq, char_t *str)
{
int rc;
a_assert(rq);
a_assert(str);
a_assert(rq->buflen == (rq->endbuf - rq->buf));
rc = ringqPutBlk(rq, (unsigned char*) str, gstrlen(str) * sizeof(char_t));
*((char_t*) rq->endp) = (char_t) '\0';
return rc;
}
/******************************************************************************/
/*
* Add a null terminator. This does NOT increase the size of the queue
*/
void ringqAddNull(ringq_t *rq)
{
a_assert(rq);
a_assert(rq->buflen == (rq->endbuf - rq->buf));
*((char_t*) rq->endp) = (char_t) '\0';
}
/******************************************************************************/
#ifdef UNICODE
/*
* Get a byte from the queue
*/
int ringqGetcA(ringq_t *rq)
{
unsigned char c;
a_assert(rq);
a_assert(rq->buflen == (rq->endbuf - rq->buf));
if (rq->servp == rq->endp) {
return -1;
}
c = *rq->servp++;
if (rq->servp >= rq->endbuf) {
rq->servp = rq->buf;
}
return c;
}
/******************************************************************************/
/*
* Add a byte to the queue. Note if being used to store strings this does not
* add a trailing '\0'. Grow the q as required.
*/
int ringqPutcA(ringq_t *rq, char c)
{
a_assert(rq);
a_assert(rq->buflen == (rq->endbuf - rq->buf));
if (ringqPutBlkMax(rq) == 0 && !ringqGrow(rq)) {
return -1;
}
*rq->endp++ = (unsigned char) c;
if (rq->endp >= rq->endbuf) {
rq->endp = rq->buf;
}
return 0;
}
/******************************************************************************/
/*
* Insert a byte at the front of the queue
*/
int ringqInsertcA(ringq_t *rq, char c)
{
a_assert(rq);
a_assert(rq->buflen == (rq->endbuf - rq->buf));
if (ringqPutBlkMax(rq) == 0 && !ringqGrow(rq)) {
return -1;
}
if (rq->servp <= rq->buf) {
rq->servp = rq->endbuf;
}
*--rq->servp = (unsigned char) c;
return 0;
}
/******************************************************************************/
/*
* Add a string to the queue. Add a trailing null (not really in the q).
* ie. beyond the last valid byte.
*/
int ringqPutStrA(ringq_t *rq, char *str)
{
int rc;
a_assert(rq);
a_assert(str);
a_assert(rq->buflen == (rq->endbuf - rq->buf));
rc = ringqPutBlk(rq, (unsigned char*) str, strlen(str));
rq->endp[0] = '\0';
return rc;
}
#endif /* UNICODE */
/******************************************************************************/
/*
* Add a block of data to the ringq. Return the number of bytes added.
* Grow the q as required.
*/
int ringqPutBlk(ringq_t *rq, unsigned char *buf, int size)
{
int this, bytes_put;
a_assert(rq);
a_assert(rq->buflen == (rq->endbuf - rq->buf));
a_assert(buf);
a_assert(0 <= size);
/*
* Loop adding the maximum bytes we can add in a single straight line copy
*/
bytes_put = 0;
while (size > 0) {
this = min(ringqPutBlkMax(rq), size);
if (this <= 0) {
if (! ringqGrow(rq)) {
break;
}
this = min(ringqPutBlkMax(rq), size);
}
memcpy(rq->endp, buf, this);
buf += this;
rq->endp += this;
size -= this;
bytes_put += this;
if (rq->endp >= rq->endbuf) {
rq->endp = rq->buf;
}
}
return bytes_put;
}
/******************************************************************************/
/*
* Get a block of data from the ringq. Return the number of bytes returned.
*/
int ringqGetBlk(ringq_t *rq, unsigned char *buf, int size)
{
int this, bytes_read;
a_assert(rq);
a_assert(rq->buflen == (rq->endbuf - rq->buf));
a_assert(buf);
a_assert(0 <= size && size < rq->buflen);
/*
* Loop getting the maximum bytes we can get in a single straight line copy
*/
bytes_read = 0;
while (size > 0) {
this = ringqGetBlkMax(rq);
this = min(this, size);
if (this <= 0) {
break;
}
memcpy(buf, rq->servp, this);
buf += this;
rq->servp += this;
size -= this;
bytes_read += this;
if (rq->servp >= rq->endbuf) {
rq->servp = rq->buf;
}
}
return bytes_read;
}
/******************************************************************************/
/*
* Return the maximum number of bytes the ring q can accept via a single
* block copy. Useful if the user is doing their own data insertion.
*/
int ringqPutBlkMax(ringq_t *rq)
{
int space, in_a_line;
a_assert(rq);
a_assert(rq->buflen == (rq->endbuf - rq->buf));
space = rq->buflen - RINGQ_LEN(rq) - 1;
in_a_line = rq->endbuf - rq->endp;
return min(in_a_line, space);
}
/******************************************************************************/
/*
* Return the maximum number of bytes the ring q can provide via a single
* block copy. Useful if the user is doing their own data retrieval.
*/
int ringqGetBlkMax(ringq_t *rq)
{
int len, in_a_line;
a_assert(rq);
a_assert(rq->buflen == (rq->endbuf - rq->buf));
len = RINGQ_LEN(rq);
in_a_line = rq->endbuf - rq->servp;
return min(in_a_line, len);
}
/******************************************************************************/
/*
* Adjust the endp pointer after the user has copied data into the queue.
*/
void ringqPutBlkAdj(ringq_t *rq, int size)
{
a_assert(rq);
a_assert(rq->buflen == (rq->endbuf - rq->buf));
a_assert(0 <= size && size < rq->buflen);
rq->endp += size;
if (rq->endp >= rq->endbuf) {
rq->endp -= rq->buflen;
}
/*
* Flush the queue if the endp pointer is corrupted via a bad size
*/
if (rq->endp >= rq->endbuf) {
error(E_L, E_LOG, T("Bad end pointer"));
ringqFlush(rq);
}
}
/******************************************************************************/
/*
* Adjust the servp pointer after the user has copied data from the queue.
*/
void ringqGetBlkAdj(ringq_t *rq, int size)
{
a_assert(rq);
a_assert(rq->buflen == (rq->endbuf - rq->buf));
a_assert(0 < size && size < rq->buflen);
rq->servp += size;
if (rq->servp >= rq->endbuf) {
rq->servp -= rq->buflen;
}
/*
* Flush the queue if the servp pointer is corrupted via a bad size
*/
if (rq->servp >= rq->endbuf) {
error(E_L, E_LOG, T("Bad serv pointer"));
ringqFlush(rq);
}
}
/******************************************************************************/
/*
* Flush all data in a ring q. Reset the pointers.
*/
void ringqFlush(ringq_t *rq)
{
a_assert(rq);
a_assert(rq->servp);
rq->servp = rq->buf;
rq->endp = rq->buf;
if (rq->servp) {
*rq->servp = '\0';
}
}
/******************************************************************************/
/*
* Grow the buffer. Return true if the buffer can be grown. Grow using
* the increment size specified when opening the ringq. Don't grow beyond
* the maximum possible size.
*/
static int ringqGrow(ringq_t *rq)
{
unsigned char *newbuf;
int len;
a_assert(rq);
if (rq->maxsize >= 0 && rq->buflen >= rq->maxsize) {
return 0;
}
len = ringqLen(rq);
if ((newbuf = balloc(B_L, rq->buflen + rq->increment)) == NULL) {
return 0;
}
ringqGetBlk(rq, newbuf, ringqLen(rq));
bfree(B_L, (char*) rq->buf);
#ifdef OLD
rq->endp = &newbuf[endp];
rq->servp = &newbuf[servp];
rq->endbuf = &newbuf[rq->buflen];
rq->buf = newbuf;
#endif
rq->buflen += rq->increment;
rq->endp = newbuf;
rq->servp = newbuf;
rq->buf = newbuf;
rq->endbuf = &rq->buf[rq->buflen];
ringqPutBlk(rq, newbuf, len);
/*
* Double the increment so the next grow will line up with balloc'ed memory
*/
rq->increment = getBinBlockSize(2 * rq->increment);
return 1;
}
/******************************************************************************/
/*
* Find the smallest binary memory size that "size" will fit into. This
* makes the ringq and ringqGrow routines much more efficient. The balloc
* routine likes powers of 2 minus 1.
*/
static int getBinBlockSize(int size)
{
int q;
size = size >> B_SHIFT;
for (q = 0; size; size >>= 1) {
q++;
}
return (1 << (B_SHIFT + q));
}
/******************************************************************************/

View File

@@ -1,193 +0,0 @@
/*
* rom.c -- Support for ROMed page retrieval.
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* This module provides web page retrieval from compiled web pages. Use the
* webcomp program to compile web pages and link into the GoAhead WebServer.
* This module uses a hashed symbol table for fast page lookup.
*
* Usage: webcomp -f webPageFileList -p Prefix >webrom.c
*/
/********************************* Includes ***********************************/
#include <stdlib.h>
#include "wsIntrn.h"
/******************************** Local Data **********************************/
#ifdef WEBS_PAGE_ROM
sym_fd_t romTab; /* Symbol table for web pages */
/*********************************** Code *************************************/
/*
* Open the ROM module
*/
int websRomOpen()
{
websRomPageIndexType *wip;
int nchars;
char_t name[SYM_MAX];
romTab = symOpen(WEBS_SYM_INIT);
for (wip = websRomPageIndex; wip->path; wip++) {
gstrncpy(name, wip->path, SYM_MAX);
nchars = gstrlen(name) - 1;
if (nchars > 0 &&
(name[nchars] == '/' || name[nchars] == '\\')) {
name[nchars] = '\0';
}
symEnter(romTab, name, valueInteger((int) wip), 0);
}
return 0;
}
/******************************************************************************/
/*
* Close the ROM module
*/
void websRomClose()
{
symClose(romTab);
}
/******************************************************************************/
/*
* Open a web page
*/
int websRomPageOpen(webs_t wp, char_t *path, int mode, int perm)
{
websRomPageIndexType *wip;
sym_t *sp;
a_assert(websValid(wp));
a_assert(path && *path);
if ((sp = symLookup(romTab, path)) == NULL) {
return -1;
}
wip = (websRomPageIndexType*) sp->content.value.integer;
wip->pos = 0;
return (wp->docfd = wip - websRomPageIndex);
}
/******************************************************************************/
/*
* Close a web page
*/
void websRomPageClose(int fd)
{
}
/******************************************************************************/
/*
* Stat a web page
*/
int websRomPageStat(char_t *path, websStatType *sbuf)
{
websRomPageIndexType *wip;
sym_t *sp;
a_assert(path && *path);
if ((sp = symLookup(romTab, path)) == NULL) {
return -1;
}
wip = (websRomPageIndexType*) sp->content.value.integer;
memset(sbuf, 0, sizeof(websStatType));
sbuf->size = wip->size;
if (wip->page == NULL) {
sbuf->isDir = 1;
}
return 0;
}
/******************************************************************************/
/*
* Read a web page
*/
int websRomPageReadData(webs_t wp, char *buf, int nBytes)
{
websRomPageIndexType *wip;
int len;
a_assert(websValid(wp));
a_assert(buf);
a_assert(wp->docfd >= 0);
wip = &websRomPageIndex[wp->docfd];
len = min(wip->size - wip->pos, nBytes);
memcpy(buf, &wip->page[wip->pos], len);
wip->pos += len;
return len;
}
/******************************************************************************/
/*
* Position a web page
*/
long websRomPageSeek(webs_t wp, long offset, int origin)
{
websRomPageIndexType *wip;
long pos;
a_assert(websValid(wp));
a_assert(origin == SEEK_SET || origin == SEEK_CUR || origin == SEEK_END);
a_assert(wp->docfd >= 0);
wip = &websRomPageIndex[wp->docfd];
if (origin != SEEK_SET && origin != SEEK_CUR && origin != SEEK_END) {
errno = EINVAL;
return -1;
}
if (wp->docfd < 0) {
errno = EBADF;
return -1;
}
pos = offset;
switch (origin) {
case SEEK_CUR:
pos = wip->pos + offset;
break;
case SEEK_END:
pos = wip->size + offset;
break;
default:
break;
}
if (pos < 0) {
errno = EBADF;
return -1;
}
return (wip->pos = pos);
}
#endif /* WEBS_PAGE_ROM */
/******************************************************************************/

View File

@@ -1,6 +0,0 @@
/*
* rtems_webserver.h --
*
*/
int rtems_initialize_webserver();

View File

@@ -1,235 +0,0 @@
/*
* security.c -- Security handler
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* This module provides a basic security policy.
*/
/********************************* Includes ***********************************/
#include "wsIntrn.h"
#include "um.h"
#ifdef DIGEST_ACCESS_SUPPORT
#include "websda.h"
#endif
/********************************** Defines ***********************************/
/*
* The following #defines change the behaviour of security in the absence
* of User Management.
* Note that use of User management functions require prior calling of
* umInit() to behave correctly
*/
#ifndef USER_MANAGEMENT_SUPPORT
#define umGetAccessMethodForURL(url) AM_FULL
#define umUserExists(userid) 0
#define umUserCanAccessURL(userid, url) 1
#define umGetUserPassword(userid) websGetPassword()
#define umGetAccessLimitSecure(accessLimit) 0
#define umGetAccessLimit(url) NULL
#endif
/******************************** Local Data **********************************/
static char_t websPassword[WEBS_MAX_PASS]; /* Access password (decoded) */
#ifdef _DEBUG
static int debugSecurity = 1;
#else
static int debugSecurity = 0;
#endif
/*********************************** Code *************************************/
/*
* Determine if this request should be honored
*/
int websSecurityHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg,
char_t *url, char_t *path, char_t *query)
{
char_t *type, *userid, *password, *accessLimit;
int flags, nRet;
accessMeth_t am;
a_assert(websValid(wp));
a_assert(url && *url);
a_assert(path && *path);
/*
* Get the critical request details
*/
type = websGetRequestType(wp);
password = websGetRequestPassword(wp);
userid = websGetRequestUserName(wp);
flags = websGetRequestFlags(wp);
/*
* Get the access limit for the URL. Exit if none found.
*/
accessLimit = umGetAccessLimit(path);
if (accessLimit == NULL) {
return 0;
}
/*
* Check to see if URL must be encrypted
*/
#ifdef WEBS_SSL_SUPPORT
nRet = umGetAccessLimitSecure(accessLimit);
if (nRet && ((flags & WEBS_SECURE) == 0)) {
websStats.access++;
websError(wp, 405, T("Access Denied\nSecure access is required."));
trace(3, T("SEC: Non-secure access attempted on <%s>\n"), path);
/* bugfix 5/24/02 -- we were leaking the memory pointed to by
* 'accessLimit'. Thanks to Simon Byholm.
*/
bfree(B_L, accessLimit);
return 1;
}
#endif
/*
* Get the access limit for the URL
*/
am = umGetAccessMethodForURL(accessLimit);
nRet = 0;
if ((flags & WEBS_LOCAL_REQUEST) && (debugSecurity == 0)) {
/*
* Local access is always allowed (defeat when debugging)
*/
} else if (am == AM_NONE) {
/*
* URL is supposed to be hidden! Make like it wasn't found.
*/
websStats.access++;
websError(wp, 400, T("Page Not Found"));
nRet = 1;
} else if (userid && *userid) {
if (!umUserExists(userid)) {
websStats.access++;
websError(wp, 401, T("Access Denied\nUnknown User"));
trace(3, T("SEC: Unknown user <%s> attempted to access <%s>\n"),
userid, path);
nRet = 1;
} else if (!umUserCanAccessURL(userid, accessLimit)) {
websStats.access++;
websError(wp, 403, T("Access Denied\nProhibited User"));
nRet = 1;
} else if (password && * password) {
char_t * userpass = umGetUserPassword(userid);
if (userpass) {
if (gstrcmp(password, userpass) != 0) {
websStats.access++;
websError(wp, 401, T("Access Denied\nWrong Password"));
trace(3, T("SEC: Password fail for user <%s>")
T("attempt to access <%s>\n"), userid, path);
nRet = 1;
} else {
/*
* User and password check out.
*/
}
bfree (B_L, userpass);
}
#ifdef DIGEST_ACCESS_SUPPORT
} else if (flags & WEBS_AUTH_DIGEST) {
char_t *digestCalc;
/*
* Check digest for equivalence
*/
wp->password = umGetUserPassword(userid);
a_assert(wp->digest);
a_assert(wp->nonce);
a_assert(wp->password);
digestCalc = websCalcDigest(wp);
a_assert(digestCalc);
if (gstrcmp(wp->digest, digestCalc) != 0) {
websStats.access++;
websError(wp, 405, T("Access Denied\nWrong Password"));
nRet = 1;
}
bfree (B_L, digestCalc);
#endif
} else {
/*
* No password has been specified
*/
#ifdef DIGEST_ACCESS_SUPPORT
if (am == AM_DIGEST) {
wp->flags |= WEBS_AUTH_DIGEST;
}
#endif
websStats.errors++;
websError(wp, 401,
T("Access to this document requires a password"));
nRet = 1;
}
} else if (am != AM_FULL) {
/*
* This will cause the browser to display a password / username
* dialog
*/
#ifdef DIGEST_ACCESS_SUPPORT
if (am == AM_DIGEST) {
wp->flags |= WEBS_AUTH_DIGEST;
}
#endif
websStats.errors++;
websError(wp, 401, T("Access to this document requires a User ID"));
nRet = 1;
}
bfree(B_L, accessLimit);
return nRet;
}
/******************************************************************************/
/*
* Delete the default security handler
*/
void websSecurityDelete()
{
websUrlHandlerDelete(websSecurityHandler);
}
/******************************************************************************/
/*
* Store the new password, expect a decoded password. Store in websPassword in
* the decoded form.
*/
void websSetPassword(char_t *password)
{
a_assert(password);
gstrncpy(websPassword, password, TSZ(websPassword));
}
/******************************************************************************/
/*
* Get password, return the decoded form
*/
char_t *websGetPassword()
{
return bstrdup(B_L, websPassword);
}
/******************************************************************************/

View File

@@ -1,791 +0,0 @@
/*
* sock.c -- Posix Socket upper layer support module for general posix use
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* $Id$
*/
/******************************** Description *********************************/
/*
* Posix Socket Module. This supports blocking and non-blocking buffered
* socket I/O.
*/
/********************************** Includes **********************************/
#include <string.h>
#include <stdlib.h>
#ifdef UEMF
#include "uemf.h"
#else
#include <socket.h>
#include <types.h>
#include <unistd.h>
#include "emfInternal.h"
#endif
/************************************ Locals **********************************/
socket_t **socketList; /* List of open sockets */
int socketMax; /* Maximum size of socket */
int socketHighestFd = -1; /* Highest socket fd opened */
/***************************** Forward Declarations ***************************/
static int socketDoOutput(socket_t *sp, char *buf, int toWrite, int *errCode);
static int tryAlternateSendTo(int sock, char *buf, int toWrite, int i,
struct sockaddr *server);
/*********************************** Code *************************************/
/*
* Write to a socket. Absorb as much data as the socket can buffer. Block if
* the socket is in blocking mode. Returns -1 on error, otherwise the number
* of bytes written.
*/
int socketWrite(int sid, char *buf, int bufsize)
{
socket_t *sp;
ringq_t *rq;
int len, bytesWritten, room;
a_assert(buf);
a_assert(bufsize >= 0);
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
/*
* Loop adding as much data to the output ringq as we can absorb. Initiate a
* flush when the ringq is too full and continue. Block in socketFlush if the
* socket is in blocking mode.
*/
rq = &sp->outBuf;
for (bytesWritten = 0; bufsize > 0; ) {
if ((room = ringqPutBlkMax(rq)) == 0) {
if (socketFlush(sid) < 0) {
return -1;
}
if ((room = ringqPutBlkMax(rq)) == 0) {
if (sp->flags & SOCKET_BLOCK) {
#if (defined (WIN) || defined (CE))
int errCode;
if (! socketWaitForEvent(sp, FD_WRITE | SOCKET_WRITABLE,
&errCode)) {
return -1;
}
#endif
continue;
}
break;
}
continue;
}
len = min(room, bufsize);
ringqPutBlk(rq, (unsigned char *) buf, len);
bytesWritten += len;
bufsize -= len;
buf += len;
}
return bytesWritten;
}
/******************************************************************************/
/*
* Write a string to a socket
*/
int socketWriteString(int sid, char_t *buf)
{
#ifdef UNICODE
char *byteBuf;
int r, len;
len = gstrlen(buf);
byteBuf = ballocUniToAsc(buf, len);
r = socketWrite(sid, byteBuf, len);
bfreeSafe(B_L, byteBuf);
return r;
#else
return socketWrite(sid, buf, strlen(buf));
#endif /* UNICODE */
}
/******************************************************************************/
/*
* Read from a socket. Return the number of bytes read if successful. This
* may be less than the requested "bufsize" and may be zero. Return -1 for
* errors. Return 0 for EOF. Otherwise return the number of bytes read.
* If this routine returns zero it indicates an EOF condition.
* which can be verified with socketEof()
* Note: this ignores the line buffer, so a previous socketGets
* which read a partial line may cause a subsequent socketRead to miss some
* data. This routine may block if the socket is in blocking mode.
*
*/
int socketRead(int sid, char *buf, int bufsize)
{
socket_t *sp;
ringq_t *rq;
int len, room, errCode, bytesRead;
a_assert(buf);
a_assert(bufsize > 0);
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
if (sp->flags & SOCKET_EOF) {
return 0;
}
rq = &sp->inBuf;
for (bytesRead = 0; bufsize > 0; ) {
len = min(ringqLen(rq), bufsize);
if (len <= 0) {
/*
* if blocking mode and already have data, exit now or it may block
* forever.
*/
if ((sp->flags & SOCKET_BLOCK) &&
(bytesRead > 0)) {
break;
}
/*
* This flush is critical for readers of datagram packets. If the
* buffer is not big enough to read the whole datagram in one hit,
* the recvfrom call will fail.
*/
ringqFlush(rq);
room = ringqPutBlkMax(rq);
len = socketGetInput(sid, (char *) rq->endp, room, &errCode);
if (len < 0) {
if (errCode == EWOULDBLOCK) {
if ((sp->flags & SOCKET_BLOCK) &&
(bytesRead == 0)) {
continue;
}
if (bytesRead >= 0) {
return bytesRead;
}
}
return -1;
} else if (len == 0) {
/*
* If bytesRead is 0, this is EOF since socketRead should never
* be called unless there is data yet to be read. Set the flag.
* Then pass back the number of bytes read.
*/
if (bytesRead == 0) {
sp->flags |= SOCKET_EOF;
}
return bytesRead;
}
ringqPutBlkAdj(rq, len);
len = min(len, bufsize);
}
memcpy(&buf[bytesRead], rq->servp, len);
ringqGetBlkAdj(rq, len);
bufsize -= len;
bytesRead += len;
}
return bytesRead;
}
/******************************************************************************/
/*
* Get a string from a socket. This returns data in *buf in a malloced string
* after trimming the '\n'. If there is zero bytes returned, *buf will be set
* to NULL. If doing non-blocking I/O, it returns -1 for error, EOF or when
* no complete line yet read. If doing blocking I/O, it will block until an
* entire line is read. If a partial line is read socketInputBuffered or
* socketEof can be used to distinguish between EOF and partial line still
* buffered. This routine eats and ignores carriage returns.
*/
int socketGets(int sid, char_t **buf)
{
socket_t *sp;
ringq_t *lq;
char c;
int rc, len;
a_assert(buf);
*buf = NULL;
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
lq = &sp->lineBuf;
while (1) {
if ((rc = socketRead(sid, &c, 1)) < 0) {
return rc;
}
if (rc == 0) {
/*
* If there is a partial line and we are at EOF, pretend we saw a '\n'
*/
if (ringqLen(lq) > 0 && (sp->flags & SOCKET_EOF)) {
c = '\n';
} else {
return -1;
}
}
/*
* If a newline is seen, return the data excluding the new line to the
* caller. If carriage return is seen, just eat it.
*/
if (c == '\n') {
len = ringqLen(lq);
if (len > 0) {
*buf = ballocAscToUni((char *)lq->servp, len);
} else {
*buf = NULL;
}
ringqFlush(lq);
return len;
} else if (c == '\r') {
continue;
}
ringqPutcA(lq, c);
}
return 0;
}
/******************************************************************************/
/*
* Flush the socket. Block if the socket is in blocking mode.
* This will return -1 on errors and 0 if successful.
*/
int socketFlush(int sid)
{
socket_t *sp;
ringq_t *rq;
int len, bytesWritten, errCode;
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
rq = &sp->outBuf;
/*
* Set the background flushing flag which socketEventProc will check to
* continue the flush.
*/
if (! (sp->flags & SOCKET_BLOCK)) {
sp->flags |= SOCKET_FLUSHING;
}
/*
* Break from loop if not blocking after initiating output. If we are blocking
* we wait for a write event.
*/
while (ringqLen(rq) > 0) {
len = ringqGetBlkMax(&sp->outBuf);
bytesWritten = socketDoOutput(sp, (char*) rq->servp, len, &errCode);
if (bytesWritten < 0) {
if (errCode == EINTR) {
continue;
} else if (errCode == EWOULDBLOCK || errCode == EAGAIN) {
#if (defined (WIN) || defined (CE))
if (sp->flags & SOCKET_BLOCK) {
int errCode;
if (! socketWaitForEvent(sp, FD_WRITE | SOCKET_WRITABLE,
&errCode)) {
return -1;
}
continue;
}
#endif
/*
* Ensure we get a FD_WRITE message when the socket can absorb
* more data (non-blocking only.) Store the user's mask if we
* haven't done it already.
*/
if (sp->saveMask < 0 ) {
sp->saveMask = sp->handlerMask;
socketRegisterInterest(sp,
sp->handlerMask | SOCKET_WRITABLE);
}
return 0;
}
return -1;
}
ringqGetBlkAdj(rq, bytesWritten);
}
/*
* If the buffer is empty, reset the ringq pointers to point to the start
* of the buffer. This is essential to ensure that datagrams get written
* in one single I/O operation.
*/
if (ringqLen(rq) == 0) {
ringqFlush(rq);
}
/*
* Restore the users mask if it was saved by the non-blocking code above.
* Note: saveMask = -1 if empty. socketRegisterInterest will set handlerMask
*/
if (sp->saveMask >= 0) {
socketRegisterInterest(sp, sp->saveMask);
sp->saveMask = -1;
}
sp->flags &= ~SOCKET_FLUSHING;
return 0;
}
/******************************************************************************/
/*
* Return the count of input characters buffered. We look at both the line
* buffer and the input (raw) buffer. Return -1 on error or EOF.
*/
int socketInputBuffered(int sid)
{
socket_t *sp;
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
if (socketEof(sid)) {
return -1;
}
return ringqLen(&sp->lineBuf) + ringqLen(&sp->inBuf);
}
/******************************************************************************/
/*
* Return true if EOF
*/
int socketEof(int sid)
{
socket_t *sp;
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
return sp->flags & SOCKET_EOF;
}
/******************************************************************************/
/*
* Return the number of bytes the socket can absorb without blocking
*/
int socketCanWrite(int sid)
{
socket_t *sp;
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
return sp->outBuf.buflen - ringqLen(&sp->outBuf) - 1;
}
/******************************************************************************/
/*
* Add one to allow the user to write exactly SOCKET_BUFSIZ
*/
void socketSetBufferSize(int sid, int in, int line, int out)
{
socket_t *sp;
if ((sp = socketPtr(sid)) == NULL) {
return;
}
if (in >= 0) {
ringqClose(&sp->inBuf);
in++;
ringqOpen(&sp->inBuf, in, in);
}
if (line >= 0) {
ringqClose(&sp->lineBuf);
line++;
ringqOpen(&sp->lineBuf, line, line);
}
if (out >= 0) {
ringqClose(&sp->outBuf);
out++;
ringqOpen(&sp->outBuf, out, out);
}
}
/******************************************************************************/
/*
* Create a user handler for this socket. The handler called whenever there
* is an event of interest as defined by handlerMask (SOCKET_READABLE, ...)
*/
void socketCreateHandler(int sid, int handlerMask, socketHandler_t handler,
int data)
{
socket_t *sp;
if ((sp = socketPtr(sid)) == NULL) {
return;
}
sp->handler = handler;
sp->handler_data = data;
socketRegisterInterest(sp, handlerMask);
}
/******************************************************************************/
/*
* Delete a handler
*/
void socketDeleteHandler(int sid)
{
socket_t *sp;
if ((sp = socketPtr(sid)) == NULL) {
return;
}
sp->handler = NULL;
socketRegisterInterest(sp, 0);
}
/******************************************************************************/
/*
* Socket output procedure. Return -1 on errors otherwise return the number
* of bytes written.
*/
static int socketDoOutput(socket_t *sp, char *buf, int toWrite, int *errCode)
{
struct sockaddr_in server;
int bytes;
a_assert(sp);
a_assert(buf);
a_assert(toWrite > 0);
a_assert(errCode);
*errCode = 0;
#if (defined (WIN) || defined (CE))
if ((sp->flags & SOCKET_ASYNC)
&& ! socketWaitForEvent(sp, FD_CONNECT, errCode)) {
return -1;
}
#endif
/*
* Write the data
*/
if (sp->flags & SOCKET_BROADCAST) {
server.sin_family = AF_INET;
#if (defined (UEMF) || defined (LITTLEFOOT))
server.sin_addr.s_addr = INADDR_BROADCAST;
#else
server.sin_addr.s_addr = inet_addr(basicGetBroadcastAddress());
#endif
server.sin_port = htons((short)(sp->port & 0xFFFF));
if ((bytes = sendto(sp->sock, buf, toWrite, 0,
(struct sockaddr *) &server, sizeof(server))) < 0) {
bytes = tryAlternateSendTo(sp->sock, buf, toWrite, 0,
(struct sockaddr *) &server);
}
} else if (sp->flags & SOCKET_DATAGRAM) {
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(sp->host);
server.sin_port = htons((short)(sp->port & 0xFFFF));
bytes = sendto(sp->sock, buf, toWrite, 0,
(struct sockaddr *) &server, sizeof(server));
} else {
bytes = send(sp->sock, buf, toWrite, 0);
}
if (bytes < 0) {
*errCode = socketGetError();
#if (defined (WIN) || defined (CE))
sp->currentEvents &= ~FD_WRITE;
#endif
return -1;
} else if (bytes == 0 && bytes != toWrite) {
*errCode = EWOULDBLOCK;
#if (defined (WIN) || defined (CE))
sp->currentEvents &= ~FD_WRITE;
#endif
return -1;
}
/*
* Ensure we get to write some more data real soon if the socket can absorb
* more data
*/
#ifndef UEMF
#ifdef WIN
if (sp->interestEvents & FD_WRITE) {
emfTime_t blockTime = { 0, 0 };
emfSetMaxBlockTime(&blockTime);
}
#endif /* WIN */
#endif
return bytes;
}
/******************************************************************************/
/*
* If the sendto failed, swap the first two bytes in the
* sockaddr structure. This is a kludge due to a change in
* VxWorks between versions 5.3 and 5.4, but we want the
* product to run on either.
*/
static int tryAlternateSendTo(int sock, char *buf, int toWrite, int i,
struct sockaddr *server)
{
#ifdef VXWORKS
char *ptr;
ptr = (char *)server;
*ptr = *(ptr+1);
*(ptr+1) = 0;
return sendto(sock, buf, toWrite, i, server, sizeof(struct sockaddr));
#else
return -1;
#endif /* VXWORKS */
}
/******************************************************************************/
/*
* Allocate a new socket structure
*/
int socketAlloc(char *host, int port, socketAccept_t accept, int flags)
{
socket_t *sp;
int sid;
if ((sid = hAllocEntry((void*) &socketList, &socketMax,
sizeof(socket_t))) < 0) {
return -1;
}
sp = socketList[sid];
sp->sid = sid;
sp->accept = accept;
sp->port = port;
sp->fileHandle = -1;
sp->saveMask = -1;
if (host) {
strncpy(sp->host, host, sizeof(sp->host));
}
/*
* Preserve only specified flags from the callers open
*/
a_assert((flags & ~(SOCKET_BROADCAST|SOCKET_DATAGRAM|SOCKET_BLOCK|
SOCKET_LISTENING)) == 0);
sp->flags = flags & (SOCKET_BROADCAST | SOCKET_DATAGRAM | SOCKET_BLOCK|
SOCKET_LISTENING);
/*
* Add one to allow the user to write exactly SOCKET_BUFSIZ
*/
ringqOpen(&sp->inBuf, SOCKET_BUFSIZ, SOCKET_BUFSIZ);
ringqOpen(&sp->outBuf, SOCKET_BUFSIZ + 1, SOCKET_BUFSIZ + 1);
ringqOpen(&sp->lineBuf, SOCKET_BUFSIZ, -1);
return sid;
}
/******************************************************************************/
/*
* Free a socket structure
*/
void socketFree(int sid)
{
socket_t *sp;
char_t buf[256];
int i;
if ((sp = socketPtr(sid)) == NULL) {
return;
}
/*
* To close a socket, remove any registered interests, set it to
* non-blocking so that the recv which follows won't block, do a
* shutdown on it so peers on the other end will receive a FIN,
* then read any data not yet retrieved from the receive buffer,
* and finally close it. If these steps are not all performed
* RESETs may be sent to the other end causing problems.
*/
socketRegisterInterest(sp, 0);
if (sp->sock >= 0) {
socketSetBlock(sid, 0);
if (shutdown(sp->sock, 1) >= 0) {
recv(sp->sock, buf, sizeof(buf), 0);
}
#if (defined (WIN) || defined (CE))
closesocket(sp->sock);
#else
close(sp->sock);
#endif
}
ringqClose(&sp->inBuf);
ringqClose(&sp->outBuf);
ringqClose(&sp->lineBuf);
bfree(B_L, sp);
socketMax = hFree((void*) &socketList, sid);
/*
* Calculate the new highest socket number
*/
socketHighestFd = -1;
for (i = 0; i < socketMax; i++) {
if ((sp = socketList[i]) == NULL) {
continue;
}
socketHighestFd = max(socketHighestFd, sp->sock);
}
}
/******************************************************************************/
/*
* Validate a socket handle
*/
socket_t *socketPtr(int sid)
{
if (sid < 0 || sid >= socketMax || socketList[sid] == NULL) {
a_assert(NULL);
errno = EBADF;
return NULL;
}
a_assert(socketList[sid]);
return socketList[sid];
}
/******************************************************************************/
/*
* Get the operating system error code
*/
int socketGetError()
{
#if (defined (WIN) || defined (CE))
switch (WSAGetLastError()) {
case WSAEWOULDBLOCK:
return EWOULDBLOCK;
case WSAECONNRESET:
return ECONNRESET;
case WSAENETDOWN:
return ENETDOWN;
case WSAEPROCLIM:
return EAGAIN;
case WSAEINTR:
return EINTR;
default:
return EINVAL;
}
#else
return errno;
#endif
}
/******************************************************************************/
/*
* Return the underlying socket handle
*/
int socketGetHandle(int sid)
{
socket_t *sp;
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
return sp->sock;
}
/******************************************************************************/
/*
* Get blocking mode
*/
int socketGetBlock(int sid)
{
socket_t *sp;
if ((sp = socketPtr(sid)) == NULL) {
a_assert(0);
return 0;
}
return (sp->flags & SOCKET_BLOCK);
}
/******************************************************************************/
/*
* Get mode
*/
int socketGetMode(int sid)
{
socket_t *sp;
if ((sp = socketPtr(sid)) == NULL) {
a_assert(0);
return 0;
}
return sp->flags;
}
/******************************************************************************/
/*
* Set mode
*/
void socketSetMode(int sid, int mode)
{
socket_t *sp;
if ((sp = socketPtr(sid)) == NULL) {
a_assert(0);
return;
}
sp->flags = mode;
}
/******************************************************************************/
/*
* Get port.
*/
int socketGetPort(int sid)
{
socket_t *sp;
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
return sp->port;
}
/******************************************************************************/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,474 +0,0 @@
/*
* sym.c -- Symbol Table module
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* This module implements a highly efficient generic symbol table with
* update and access routines. Symbols are simple character strings and
* the values they take can be flexible types as defined by value_t.
* This modules allows multiple symbol tables to be created.
*/
/********************************* Includes ***********************************/
#ifdef UEMF
#include "uemf.h"
#else
#include "basic/basicInternal.h"
#endif
/********************************* Defines ************************************/
typedef struct { /* Symbol table descriptor */
int inuse; /* Is this entry in use */
int hash_size; /* Size of the table below */
sym_t **hash_table; /* Allocated at run time */
} sym_tabent_t;
/********************************* Globals ************************************/
static sym_tabent_t **sym; /* List of symbol tables */
static int symMax; /* One past the max symbol table */
static int symOpenCount = 0; /* Count of apps using sym */
static int htIndex; /* Current location in table */
static sym_t* next; /* Next symbol in iteration */
/**************************** Forward Declarations ****************************/
static int hashIndex(sym_tabent_t *tp, char_t *name);
static sym_t *hash(sym_tabent_t *tp, char_t *name);
static int calcPrime(int size);
/*********************************** Code *************************************/
/*
* Open the symbol table subSystem.
*/
int symSubOpen()
{
if (++symOpenCount == 1) {
symMax = 0;
sym = NULL;
}
return 0;
}
/******************************************************************************/
/*
* Close the symbol table subSystem.
*/
void symSubClose()
{
if (--symOpenCount <= 0) {
symOpenCount = 0;
}
}
/******************************************************************************/
/*
* Create a symbol table.
*/
sym_fd_t symOpen(int hash_size)
{
sym_fd_t sd;
sym_tabent_t *tp;
a_assert(hash_size > 2);
/*
* Create a new handle for this symbol table
*/
if ((sd = hAlloc((void*) &sym)) < 0) {
return -1;
}
/*
* Create a new symbol table structure and zero
*/
if ((tp = (sym_tabent_t*) balloc(B_L, sizeof(sym_tabent_t))) == NULL) {
symMax = hFree((void*) &sym, sd);
return -1;
}
memset(tp, 0, sizeof(sym_tabent_t));
if (sd >= symMax) {
symMax = sd + 1;
}
a_assert(0 <= sd && sd < symMax);
sym[sd] = tp;
/*
* Now create the hash table for fast indexing.
*/
tp->hash_size = calcPrime(hash_size);
tp->hash_table = (sym_t**) balloc(B_L, tp->hash_size * sizeof(sym_t*));
a_assert(tp->hash_table);
memset(tp->hash_table, 0, tp->hash_size * sizeof(sym_t*));
return sd;
}
/******************************************************************************/
/*
* Close this symbol table. Call a cleanup function to allow the caller
* to free resources associated with each symbol table entry.
*/
void symClose(sym_fd_t sd)
{
sym_tabent_t *tp;
sym_t *sp, *forw;
int i;
a_assert(0 <= sd && sd < symMax);
tp = sym[sd];
a_assert(tp);
/*
* Free all symbols in the hash table, then the hash table itself.
*/
for (i = 0; i < tp->hash_size; i++) {
for (sp = tp->hash_table[i]; sp; sp = forw) {
forw = sp->forw;
valueFree(&sp->name);
valueFree(&sp->content);
bfree(B_L, (void*) sp);
sp = forw;
}
}
bfree(B_L, (void*) tp->hash_table);
symMax = hFree((void*) &sym, sd);
bfree(B_L, (void*) tp);
}
/******************************************************************************/
/*
* Return the first symbol in the hashtable if there is one. This call is used
* as the first step in traversing the table. A call to symFirst should be
* followed by calls to symNext to get all the rest of the entries.
*/
sym_t* symFirst(sym_fd_t sd)
{
sym_tabent_t *tp;
sym_t *sp, *forw;
int i;
a_assert(0 <= sd && sd < symMax);
tp = sym[sd];
a_assert(tp);
/*
* Find the first symbol in the hashtable and return a pointer to it.
*/
for (i = 0; i < tp->hash_size; i++) {
for (sp = tp->hash_table[i]; sp; sp = forw) {
forw = sp->forw;
if (forw == NULL) {
htIndex = i + 1;
next = tp->hash_table[htIndex];
} else {
htIndex = i;
next = forw;
}
return sp;
}
}
return NULL;
}
/******************************************************************************/
/*
* Return the next symbol in the hashtable if there is one. See symFirst.
*/
sym_t* symNext(sym_fd_t sd)
{
sym_tabent_t *tp;
sym_t *sp, *forw;
int i;
a_assert(0 <= sd && sd < symMax);
tp = sym[sd];
a_assert(tp);
/*
* Find the first symbol in the hashtable and return a pointer to it.
*/
for (i = htIndex; i < tp->hash_size; i++) {
for (sp = next; sp; sp = forw) {
forw = sp->forw;
if (forw == NULL) {
htIndex = i + 1;
next = tp->hash_table[htIndex];
} else {
htIndex = i;
next = forw;
}
return sp;
}
next = tp->hash_table[i + 1];
}
return NULL;
}
/******************************************************************************/
/*
* Lookup a symbol and return a pointer to the symbol entry. If not present
* then return a NULL.
*/
sym_t *symLookup(sym_fd_t sd, char_t *name)
{
sym_tabent_t *tp;
sym_t *sp;
char_t *cp;
a_assert(0 <= sd && sd < symMax);
if ((tp = sym[sd]) == NULL) {
return NULL;
}
if (name == NULL || *name == '\0') {
return NULL;
}
/*
* Do an initial hash and then follow the link chain to find the right entry
*/
for (sp = hash(tp, name); sp; sp = sp->forw) {
cp = sp->name.value.string;
if (cp[0] == name[0] && gstrcmp(cp, name) == 0) {
break;
}
}
return sp;
}
/******************************************************************************/
/*
* Enter a symbol into the table. If already there, update its value.
* Always succeeds if memory available. We allocate a copy of "name" here
* so it can be a volatile variable. The value "v" is just a copy of the
* passed in value, so it MUST be persistent.
*/
sym_t *symEnter(sym_fd_t sd, char_t *name, value_t v, int arg)
{
sym_tabent_t *tp;
sym_t *sp, *last;
char_t *cp;
int hindex;
a_assert(name);
a_assert(0 <= sd && sd < symMax);
tp = sym[sd];
a_assert(tp);
/*
* Calculate the first daisy-chain from the hash table. If non-zero, then
* we have daisy-chain, so scan it and look for the symbol.
*/
last = NULL;
hindex = hashIndex(tp, name);
if ((sp = tp->hash_table[hindex]) != NULL) {
for (; sp; sp = sp->forw) {
cp = sp->name.value.string;
if (cp[0] == name[0] && gstrcmp(cp, name) == 0) {
break;
}
last = sp;
}
if (sp) {
/*
* Found, so update the value
* If the caller stores handles which require freeing, they
* will be lost here. It is the callers responsibility to free
* resources before overwriting existing contents. We will here
* free allocated strings which occur due to value_instring().
* We should consider providing the cleanup function on the open rather
* than the close and then we could call it here and solve the problem.
*/
if (sp->content.valid) {
valueFree(&sp->content);
}
sp->content = v;
sp->arg = arg;
return sp;
}
/*
* Not found so allocate and append to the daisy-chain
*/
sp = (sym_t*) balloc(B_L, sizeof(sym_t));
if (sp == NULL) {
return NULL;
}
sp->name = valueString(name, VALUE_ALLOCATE);
sp->content = v;
sp->forw = (sym_t*) NULL;
sp->arg = arg;
last->forw = sp;
} else {
/*
* Daisy chain is empty so we need to start the chain
*/
sp = (sym_t*) balloc(B_L, sizeof(sym_t));
if (sp == NULL) {
return NULL;
}
tp->hash_table[hindex] = sp;
tp->hash_table[hashIndex(tp, name)] = sp;
sp->forw = (sym_t*) NULL;
sp->content = v;
sp->arg = arg;
sp->name = valueString(name, VALUE_ALLOCATE);
}
return sp;
}
/******************************************************************************/
/*
* Delete a symbol from a table
*/
int symDelete(sym_fd_t sd, char_t *name)
{
sym_tabent_t *tp;
sym_t *sp, *last;
char_t *cp;
int hindex;
a_assert(name && *name);
a_assert(0 <= sd && sd < symMax);
tp = sym[sd];
a_assert(tp);
/*
* Calculate the first daisy-chain from the hash table. If non-zero, then
* we have daisy-chain, so scan it and look for the symbol.
*/
last = NULL;
hindex = hashIndex(tp, name);
if ((sp = tp->hash_table[hindex]) != NULL) {
for ( ; sp; sp = sp->forw) {
cp = sp->name.value.string;
if (cp[0] == name[0] && gstrcmp(cp, name) == 0) {
break;
}
last = sp;
}
}
if (sp == (sym_t*) NULL) { /* Not Found */
return -1;
}
/*
* Unlink and free the symbol. Last will be set if the element to be deleted
* is not first in the chain.
*/
if (last) {
last->forw = sp->forw;
} else {
tp->hash_table[hindex] = sp->forw;
}
valueFree(&sp->name);
valueFree(&sp->content);
bfree(B_L, (void*) sp);
return 0;
}
/******************************************************************************/
/*
* Hash a symbol and return a pointer to the hash daisy-chain list
* All symbols reside on the chain (ie. none stored in the hash table itself)
*/
static sym_t *hash(sym_tabent_t *tp, char_t *name)
{
a_assert(tp);
return tp->hash_table[hashIndex(tp, name)];
}
/******************************************************************************/
/*
* Compute the hash function and return an index into the hash table
* We use a basic additive function that is then made modulo the size of the
* table.
*/
static int hashIndex(sym_tabent_t *tp, char_t *name)
{
unsigned int sum;
int i;
a_assert(tp);
/*
* Add in each character shifted up progressively by 7 bits. The shift
* amount is rounded so as to not shift too far. It thus cycles with each
* new cycle placing character shifted up by one bit.
*/
i = 0;
sum = 0;
while (*name) {
sum += (((int) *name++) << i);
i = (i + 7) % (BITS(int) - BITSPERBYTE);
}
return sum % tp->hash_size;
}
/******************************************************************************/
/*
* Check if this number is a prime
*/
static int isPrime(int n)
{
int i, max;
a_assert(n > 0);
max = n / 2;
for (i = 2; i <= max; i++) {
if (n % i == 0) {
return 0;
}
}
return 1;
}
/******************************************************************************/
/*
* Calculate the largest prime smaller than size.
*/
static int calcPrime(int size)
{
int count;
a_assert(size > 0);
for (count = size; count > 0; count--) {
if (isPrime(count)) {
return count;
}
}
return 1;
}
/******************************************************************************/

View File

@@ -1,293 +0,0 @@
/*
* uemf.c -- GoAhead Micro Embedded Management Framework
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/********************************** Description *******************************/
/*
* This module provides compatibility with the full GoAhead EMF.
* It is a collection of routines which permits the GoAhead WebServer to
* run stand-alone and to also load as a solution pack under the GoAhead EMF.
*/
/*********************************** Includes *********************************/
#include "uemf.h"
/********************************** Local Data ********************************/
int emfInst; /* Application instance handle */
/****************************** Forward Declarations **************************/
extern void defaultErrorHandler(int etype, char_t *buf);
static void (*errorHandler)(int etype, char_t *msg) = defaultErrorHandler;
extern void defaultTraceHandler(int level, char_t *buf);
static void (*traceHandler)(int level, char_t *buf) = defaultTraceHandler;
/************************************* Code ***********************************/
/*
* Error message that doesn't need user attention. Customize this code
* to direct error messages to wherever the developer wishes
*/
void error(E_ARGS_DEC, int etype, char_t *fmt, ...)
{
va_list args;
char_t *fmtBuf, *buf;
va_start(args, fmt);
fmtValloc(&fmtBuf, E_MAX_ERROR, fmt, args);
if (etype == E_LOG) {
fmtAlloc(&buf, E_MAX_ERROR, T("%s\n"), fmtBuf);
/*#ifdef DEV*/
} else if (etype == E_ASSERT) {
fmtAlloc(&buf, E_MAX_ERROR,
T("Assertion %s, failed at %s %d\n"), fmtBuf, E_ARGS);
/*#endif*/
} else if (etype == E_USER) {
fmtAlloc(&buf, E_MAX_ERROR, T("%s\n"), fmtBuf);
}
/*
* bugfix -- if etype is not E_LOG, E_ASSERT, or E_USER, the call to
* bfreeSafe(B_L, buf) below will fail, because 'buf' is randomly
* initialized. To be nice, we format a message saying that this is an
* unknown message type, and in doing so give buf a valid value. Thanks
* to Simon Byholm.
*/
else {
fmtAlloc(&buf, E_MAX_ERROR, T("Unknown error"));
}
va_end(args);
bfree(B_L, fmtBuf);
if (errorHandler) {
errorHandler(etype, buf);
}
bfreeSafe(B_L, buf);
}
/******************************************************************************/
/*
* Replace the default error handler. Return pointer to old error handler.
*/
void (*errorSetHandler(void (*function)(int etype, char_t *msg))) \
(int etype, char_t *msg)
{
void (*oldHandler)(int etype, char_t *buf);
oldHandler = errorHandler;
errorHandler = function;
return oldHandler;
}
/******************************************************************************/
/*
* Trace log. Customize this function to log trace output
*/
void trace(int level, char_t *fmt, ...)
{
va_list args;
char_t *buf;
va_start(args, fmt);
fmtValloc(&buf, VALUE_MAX_STRING, fmt, args);
if (traceHandler) {
traceHandler(level, buf);
}
bfreeSafe(B_L, buf);
va_end(args);
}
/******************************************************************************/
/*
* Trace log. Customize this function to log trace output
*/
void traceRaw(char_t *buf)
{
if (traceHandler) {
traceHandler(0, buf);
}
}
/******************************************************************************/
/*
* Replace the default trace handler. Return a pointer to the old handler.
*/
void (*traceSetHandler(void (*function)(int level, char_t *buf)))
(int level, char *buf)
{
void (*oldHandler)(int level, char_t *buf);
oldHandler = traceHandler;
if (function) {
traceHandler = function;
}
return oldHandler;
}
/******************************************************************************/
/*
* Save the instance handle
*/
void emfInstSet(int inst)
{
emfInst = inst;
}
/******************************************************************************/
/*
* Get the instance handle
*/
int emfInstGet()
{
return emfInst;
}
/******************************************************************************/
/*
* Convert a string to lower case
*/
char_t *strlower(char_t *string)
{
char_t *s;
a_assert(string);
if (string == NULL) {
return NULL;
}
s = string;
while (*s) {
if (gisupper(*s)) {
*s = (char_t) gtolower(*s);
}
s++;
}
*s = '\0';
return string;
}
/******************************************************************************/
/*
* Convert a string to upper case
*/
char_t *strupper(char_t *string)
{
char_t *s;
a_assert(string);
if (string == NULL) {
return NULL;
}
s = string;
while (*s) {
if (gislower(*s)) {
*s = (char_t) gtoupper(*s);
}
s++;
}
*s = '\0';
return string;
}
/******************************************************************************/
/*
* Convert integer to ascii string. Allow a NULL string in which case we
* allocate a dynamic buffer.
*/
char_t *stritoa(int n, char_t *string, int width)
{
char_t *cp, *lim, *s;
char_t buf[16]; /* Just temp to hold number */
int next, minus;
a_assert(string && width > 0);
if (string == NULL) {
if (width == 0) {
width = 10;
}
if ((string = balloc(B_L, width + 1)) == NULL) {
return NULL;
}
}
if (n < 0) {
minus = 1;
n = -n;
width--;
} else {
minus = 0;
}
cp = buf;
lim = &buf[width - 1];
while (n > 9 && cp < lim) {
next = n;
n /= 10;
*cp++ = (char_t) (next - n * 10 + '0');
}
if (cp < lim) {
*cp++ = (char_t) (n + '0');
}
s = string;
if (minus) {
*s++ = '-';
}
while (cp > buf) {
*s++ = *--cp;
}
*s++ = '\0';
return string;
}
/******************************************************************************/
/*
* Stubs
*/
char_t *basicGetProduct()
{
return T("uemf");
}
char_t *basicGetAddress()
{
return T("localhost");
}
int errorOpen(char_t *pname)
{
return 0;
}
void errorClose()
{
}
/******************************************************************************/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,183 +0,0 @@
/*
* um.h -- GoAhead User Management public header
*
* Copyright (c) GoAhead Software Inc., 1992-2000. All Rights Reserved.
*
* See the file "license.txt" for information on usage and redistribution
*
* $Id$
*/
#ifndef _h_UM
#define _h_UM 1
/******************************** Description *********************************/
/*
* GoAhead User Management header. This defines the User Management
* public APIs. Include this header for files that contain access to
* user inquiry or management.
*/
/********************************* Includes ***********************************/
#ifndef UEMF
#include "basic/basic.h"
#include "emf/emf.h"
#else
#include "uemf.h"
#endif
/********************************** Defines ***********************************/
/*
* Error Return Flags
*/
#define UM_OK 0
#define UM_ERR_GENERAL -1
#define UM_ERR_NOT_FOUND -2
#define UM_ERR_PROTECTED -3
#define UM_ERR_DUPLICATE -4
#define UM_ERR_IN_USE -5
#define UM_ERR_BAD_NAME -6
#define UM_ERR_BAD_PASSWORD -7
/*
* Privilege Masks
*/
#define PRIV_NONE 0x00
#define PRIV_READ 0x01
#define PRIV_WRITE 0x02
#define PRIV_ADMIN 0x04
/*
* User classes
*/
typedef short bool_t;
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
typedef enum {
AM_NONE = 0,
AM_FULL,
AM_BASIC,
AM_DIGEST,
AM_INVALID
} accessMeth_t;
/********************************** Prototypes ********************************/
/*
* umOpen() must be called before accessing User Management functions
*/
extern int umOpen();
/*
* umClose() should be called before shutdown to free memory
*/
extern void umClose();
/*
* umCommit() persists the user management database
*/
extern int umCommit(char_t *filename);
/*
* umRestore() loads the user management database
*/
extern int umRestore(char_t *filename);
/*
* umUser functions use a user ID for a key
*/
extern int umAddUser(char_t *user, char_t *password,
char_t *group, bool_t protect, bool_t disabled);
extern int umDeleteUser(char_t *user);
extern char_t *umGetFirstUser();
extern char_t *umGetNextUser(char_t *lastUser);
extern bool_t umUserExists(char_t *user);
extern char_t *umGetUserPassword(char_t *user);
extern int umSetUserPassword(char_t *user, char_t *password);
extern char_t *umGetUserGroup(char_t *user);
extern int umSetUserGroup(char_t *user, char_t *password);
extern bool_t umGetUserEnabled(char_t *user);
extern int umSetUserEnabled(char_t *user, bool_t enabled);
extern bool_t umGetUserProtected(char_t *user);
extern int umSetUserProtected(char_t *user, bool_t protect);
/*
* umGroup functions use a group name for a key
*/
extern int umAddGroup(char_t *group, short privilege,
accessMeth_t am, bool_t protect, bool_t disabled);
extern int umDeleteGroup(char_t *group);
extern char_t *umGetFirstGroup();
extern char_t *umGetNextGroup(char_t *lastUser);
extern bool_t umGroupExists(char_t *group);
extern bool_t umGetGroupInUse(char_t *group);
extern accessMeth_t umGetGroupAccessMethod(char_t *group);
extern int umSetGroupAccessMethod(char_t *group, accessMeth_t am);
extern bool_t umGetGroupEnabled(char_t *group);
extern int umSetGroupEnabled(char_t *group, bool_t enabled);
extern short umGetGroupPrivilege(char_t *group);
extern int umSetGroupPrivilege(char_t *group, short privileges);
extern bool_t umGetGroupProtected(char_t *group);
extern int umSetGroupProtected(char_t *group, bool_t protect);
/*
* umAccessLimit functions use a URL as a key
*/
extern int umAddAccessLimit(char_t *url, accessMeth_t am,
short secure, char_t *group);
extern int umDeleteAccessLimit(char_t *url);
extern char_t *umGetFirstAccessLimit();
extern char_t *umGetNextAccessLimit(char_t *lastUser);
/*
* Returns the name of an ancestor access limit if
*/
extern char_t *umGetAccessLimit(char_t *url);
extern bool_t umAccessLimitExists(char_t *url);
extern accessMeth_t umGetAccessLimitMethod(char_t *url);
extern int umSetAccessLimitMethod(char_t *url, accessMeth_t am);
extern short umGetAccessLimitSecure(char_t *url);
extern int umSetAccessLimitSecure(char_t *url, short secure);
extern char_t *umGetAccessLimitGroup(char_t *url);
extern int umSetAccessLimitGroup(char_t *url, char_t *group);
/*
* Convenience Functions
*/
extern accessMeth_t umGetAccessMethodForURL(char_t *url);
extern bool_t umUserCanAccessURL(char_t *user, char_t *url);
#endif /* _h_UM */
/******************************************************************************/

View File

@@ -1,641 +0,0 @@
/*
* umui.c -- User Management GoForm Processing
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* This module provides GoForm functions for User management
*/
/********************************* Includes ***********************************/
#include "wsIntrn.h"
#include "um.h"
/********************************* Defines ************************************/
#define NONE_OPTION T("<NONE>")
#define MSG_START T("<body><h2>")
#define MSG_END T("</h2></body>")
/**************************** Forward Declarations ****************************/
static void formAddUser(webs_t wp, char_t *path, char_t *query);
static void formDeleteUser(webs_t wp, char_t *path, char_t *query);
static void formDisplayUser(webs_t wp, char_t *path, char_t *query);
static int aspGenerateUserList(int eid, webs_t wp,
int argc, char_t **argv);
static void formAddGroup(webs_t wp, char_t *path, char_t *query);
static void formDeleteGroup(webs_t wp, char_t *path, char_t *query);
static int aspGenerateGroupList(int eid, webs_t wp,
int argc, char_t **argv);
static void formAddAccessLimit(webs_t wp, char_t *path, char_t *query);
static void formDeleteAccessLimit(webs_t wp, char_t *path, char_t *query);
static int aspGenerateAccessLimitList(int eid, webs_t wp,
int argc, char_t **argv);
static int aspGenerateAccessMethodList(int eid, webs_t wp,
int argc, char_t **argv);
static int aspGeneratePrivilegeList(int eid, webs_t wp,
int argc, char_t **argv);
static void formSaveUserManagement(webs_t wp, char_t *path, char_t *query);
static void formLoadUserManagement(webs_t wp, char_t *path, char_t *query);
static void websMsgStart(webs_t wp);
static void websMsgEnd(webs_t wp);
/*********************************** Code *************************************/
/*
* Set up the User Management form handlers
*/
void formDefineUserMgmt(void)
{
websAspDefine(T("MakeGroupList"), aspGenerateGroupList);
websAspDefine(T("MakeUserList"), aspGenerateUserList);
websAspDefine(T("MakeAccessLimitList"), aspGenerateAccessLimitList);
websAspDefine(T("MakeAccessMethodList"), aspGenerateAccessMethodList);
websAspDefine(T("MakePrivilegeList"), aspGeneratePrivilegeList);
websFormDefine(T("AddUser"), formAddUser);
websFormDefine(T("DeleteUser"), formDeleteUser);
websFormDefine(T("DisplayUser"), formDisplayUser);
websFormDefine(T("AddGroup"), formAddGroup);
websFormDefine(T("DeleteGroup"), formDeleteGroup);
websFormDefine(T("AddAccessLimit"), formAddAccessLimit);
websFormDefine(T("DeleteAccessLimit"), formDeleteAccessLimit);
websFormDefine(T("SaveUserManagement"), formSaveUserManagement);
websFormDefine(T("LoadUserManagement"), formLoadUserManagement);
}
/******************************************************************************/
/*
* Add a user
*/
static void formAddUser(webs_t wp, char_t *path, char_t *query)
{
char_t *userid, *pass1, *pass2, *group, *enabled, *ok;
bool_t bDisable;
int nCheck;
a_assert(wp);
userid = websGetVar(wp, T("user"), T(""));
pass1 = websGetVar(wp, T("password"), T(""));
pass2 = websGetVar(wp, T("passconf"), T(""));
group = websGetVar(wp, T("group"), T(""));
enabled = websGetVar(wp, T("enabled"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Add User Cancelled"));
} else if (gstrcmp(pass1, pass2) != 0) {
websWrite(wp, T("Confirmation Password did not match."));
} else {
if (enabled && *enabled && (gstrcmp(enabled, T("on")) == 0)) {
bDisable = FALSE;
} else {
bDisable = TRUE;
}
nCheck = umAddUser(userid, pass1, group, 0, bDisable);
if (nCheck != 0) {
char_t * strError;
switch (nCheck) {
case UM_ERR_DUPLICATE:
strError = T("User already exists.");
break;
case UM_ERR_BAD_NAME:
strError = T("Invalid user name.");
break;
case UM_ERR_BAD_PASSWORD:
strError = T("Invalid password.");
break;
case UM_ERR_NOT_FOUND:
strError = T("Invalid or unselected group.");
break;
default:
strError = T("Error writing user record.");
break;
}
websWrite(wp, T("Unable to add user, \"%s\". %s"),
userid, strError);
} else {
websWrite(wp, T("User, \"%s\" was successfully added."),
userid);
}
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Delete a user
*/
static void formDeleteUser(webs_t wp, char_t *path, char_t *query)
{
char_t *userid, *ok;
a_assert(wp);
userid = websGetVar(wp, T("user"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Delete User Cancelled"));
} else if (umUserExists(userid) == FALSE) {
websWrite(wp, T("ERROR: User \"%s\" not found"), userid);
} else if (umGetUserProtected(userid)) {
websWrite(wp, T("ERROR: User, \"%s\" is delete-protected."), userid);
} else if (umDeleteUser(userid) != 0) {
websWrite(wp, T("ERROR: Unable to delete user, \"%s\" "), userid);
} else {
websWrite(wp, T("User, \"%s\" was successfully deleted."), userid);
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Display the user info
*/
static void formDisplayUser(webs_t wp, char_t *path, char_t *query)
{
char_t *userid, *ok, *temp;
bool_t enabled;
a_assert(wp);
userid = websGetVar(wp, T("user"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websWrite(wp, T("<body>"));
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Display User Cancelled"));
} else if (umUserExists(userid) == FALSE) {
websWrite(wp, T("ERROR: User <b>%s</b> not found.\n"), userid);
} else {
websWrite(wp, T("<h2>User ID: <b>%s</b></h2>\n"), userid);
temp = umGetUserGroup(userid);
websWrite(wp, T("<h3>User Group: <b>%s</b></h3>\n"), temp);
enabled = umGetUserEnabled(userid);
websWrite(wp, T("<h3>Enabled: <b>%d</b></h3>\n"), enabled);
}
websWrite(wp, T("</body>\n"));
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Generate HTML to create a list box containing the users
*/
static int aspGenerateUserList(int eid, webs_t wp, int argc, char_t **argv)
{
char_t *userid;
int row, nBytesSent, nBytes;
a_assert(wp);
nBytes = websWrite(wp,
T("<SELECT NAME=\"user\" SIZE=\"3\" TITLE=\"Select a User\">"));
row = 0;
userid = umGetFirstUser();
nBytesSent = 0;
while (userid && (nBytes > 0)) {
nBytes = websWrite(wp, T("<OPTION VALUE=\"%s\">%s\n"),
userid, userid);
userid = umGetNextUser(userid);
nBytesSent += nBytes;
}
nBytesSent += websWrite(wp, T("</SELECT>"));
return nBytesSent;
}
/******************************************************************************/
/*
* Add a group
*/
static void formAddGroup(webs_t wp, char_t *path, char_t *query)
{
char_t *group, *enabled, *privilege, *method, *ok, *pChar;
int nCheck;
short priv;
accessMeth_t am;
bool_t bDisable;
a_assert(wp);
group = websGetVar(wp, T("group"), T(""));
method = websGetVar(wp, T("method"), T(""));
enabled = websGetVar(wp, T("enabled"), T(""));
privilege = websGetVar(wp, T("privilege"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Add Group Cancelled."));
} else if ((group == NULL) || (*group == 0)) {
websWrite(wp, T("No Group Name was entered."));
} else if (umGroupExists(group)) {
websWrite(wp, T("ERROR: Group, \"%s\" already exists."), group);
} else {
if (privilege && *privilege) {
/*
* privilege is a mulitple <SELECT> var, and must be parsed.
* Values for these variables are space delimited.
*/
priv = 0;
for (pChar = privilege; *pChar; pChar++) {
if (*pChar == ' ') {
*pChar = '\0';
priv |= gatoi(privilege);
*pChar = ' ';
privilege = pChar + 1;
}
}
priv |= gatoi(privilege);
} else {
priv = 0;
}
if (method && *method) {
am = (accessMeth_t) gatoi(method);
} else {
am = AM_FULL;
}
if (enabled && *enabled && (gstrcmp(enabled, T("on")) == 0)) {
bDisable = FALSE;
} else {
bDisable = TRUE;
}
nCheck = umAddGroup(group, priv, am, 0, bDisable);
if (nCheck != 0) {
websWrite(wp, T("Unable to add group, \"%s\", code: %d "),
group, nCheck);
} else {
websWrite(wp, T("Group, \"%s\" was successfully added."),
group);
}
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Delete a group
*/
static void formDeleteGroup(webs_t wp, char_t *path, char_t *query)
{
char_t *group, *ok;
a_assert(wp);
group = websGetVar(wp, T("group"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Delete Group Cancelled."));
} else if ((group == NULL) || (*group == '\0')) {
websWrite(wp, T("ERROR: No group was selected."));
} else if (umGetGroupProtected(group)) {
websWrite(wp, T("ERROR: Group, \"%s\" is delete-protected."), group);
} else if (umGetGroupInUse(group)) {
websWrite(wp, T("ERROR: Group, \"%s\" is being used."), group);
} else if (umDeleteGroup(group) != 0) {
websWrite(wp, T("ERROR: Unable to delete group, \"%s\" "), group);
} else {
websWrite(wp, T("Group, \"%s\" was successfully deleted."), group);
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Generate HTML to create a list box containing the groups
*/
static int aspGenerateGroupList(int eid, webs_t wp, int argc, char_t **argv)
{
char_t *group;
int row, nBytesSent, nBytes;
a_assert(wp);
row = 0;
nBytesSent = 0;
nBytes = websWrite(wp,
T("<SELECT NAME=\"group\" SIZE=\"3\" TITLE=\"Select a Group\">"));
/*
* Add a special "<NONE>" element to allow de-selection
*/
nBytes = websWrite(wp, T("<OPTION VALUE=\"\">[NONE]\n"));
group = umGetFirstGroup();
while (group && (nBytes > 0)) {
nBytes = websWrite(wp, T("<OPTION VALUE=\"%s\">%s\n"), group, group);
group = umGetNextGroup(group);
nBytesSent += nBytes;
}
nBytesSent += websWrite(wp, T("</SELECT>"));
return nBytesSent;
}
/******************************************************************************/
/*
* Add an access limit
*/
static void formAddAccessLimit(webs_t wp, char_t *path, char_t *query)
{
char_t *url, *method, *group, *secure, *ok;
int nCheck;
accessMeth_t am;
short nSecure;
a_assert(wp);
url = websGetVar(wp, T("url"), T(""));
group = websGetVar(wp, T("group"), T(""));
method = websGetVar(wp, T("method"), T(""));
secure = websGetVar(wp, T("secure"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Add Access Limit Cancelled."));
} else if ((url == NULL) || (*url == 0)) {
websWrite(wp, T("ERROR: No URL was entered."));
} else if (umAccessLimitExists(url)) {
websWrite(wp, T("ERROR: An Access Limit for [%s] already exists."),
url);
} else {
if (method && *method) {
am = (accessMeth_t) gatoi(method);
} else {
am = AM_FULL;
}
if (secure && *secure) {
nSecure = (short) gatoi(secure);
} else {
nSecure = 0;
}
nCheck = umAddAccessLimit(url, am, nSecure, group);
if (nCheck != 0) {
websWrite(wp, T("Unable to add Access Limit for [%s]"), url);
} else {
websWrite(wp, T("Access limit for [%s], was successfully added."),
url);
}
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Delete an Access Limit
*/
static void formDeleteAccessLimit(webs_t wp, char_t *path, char_t *query)
{
char_t *url, *ok;
a_assert(wp);
url = websGetVar(wp, T("url"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Delete Access Limit Cancelled"));
} else if (umDeleteAccessLimit(url) != 0) {
websWrite(wp, T("ERROR: Unable to delete Access Limit for [%s]"),
url);
} else {
websWrite(wp, T("Access Limit for [%s], was successfully deleted."),
url);
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Generate HTML to create a list box containing the access limits
*/
static int aspGenerateAccessLimitList(int eid, webs_t wp,
int argc, char_t **argv)
{
char_t *url;
int row, nBytesSent, nBytes;
a_assert(wp);
row = nBytesSent = 0;
url = umGetFirstAccessLimit();
nBytes = websWrite(wp,
T("<SELECT NAME=\"url\" SIZE=\"3\" TITLE=\"Select a URL\">"));
while (url && (nBytes > 0)) {
nBytes = websWrite(wp, T("<OPTION VALUE=\"%s\">%s\n"), url, url);
url = umGetNextAccessLimit(url);
nBytesSent += nBytes;
}
nBytesSent += websWrite(wp, T("</SELECT>"));
return nBytesSent;
}
/******************************************************************************/
/*
* Generate HTML to create a list box containing the access methods
*/
static int aspGenerateAccessMethodList(int eid, webs_t wp,
int argc, char_t **argv)
{
int nBytes;
a_assert(wp);
nBytes = websWrite(wp,
T("<SELECT NAME=\"method\" SIZE=\"3\" TITLE=\"Select a Method\">"));
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">FULL ACCESS\n"),
AM_FULL);
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">BASIC ACCESS\n"),
AM_BASIC);
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\" SELECTED>DIGEST ACCESS\n"),
AM_DIGEST);
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">NO ACCESS\n"),
AM_NONE);
nBytes += websWrite(wp, T("</SELECT>"));
return nBytes;
}
/******************************************************************************/
/*
* Generate HTML to create a list box containing privileges
*/
static int aspGeneratePrivilegeList(int eid, webs_t wp,
int argc, char_t **argv)
{
int nBytes;
a_assert(wp);
nBytes = websWrite(wp, T("<SELECT NAME=\"privilege\" SIZE=\"3\" "));
nBytes += websWrite(wp, T("MULTIPLE TITLE=\"Choose Privileges\">"));
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">READ\n"), PRIV_READ);
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">EXECUTE\n"), PRIV_WRITE);
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">ADMINISTRATE\n"),
PRIV_ADMIN);
nBytes += websWrite(wp, T("</SELECT>"));
return nBytes;
}
/******************************************************************************/
/*
* Save the user management configuration to a file
*/
static void formSaveUserManagement(webs_t wp, char_t *path, char_t *query)
{
char_t *ok;
a_assert(wp);
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Save Cancelled."));
} else if (umCommit(NULL) != 0) {
websWrite(wp, T("ERROR: Unable to save user configuration."));
} else {
websWrite(wp, T("User configuration was saved successfully."));
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Load the user management configuration from a file
*/
static void formLoadUserManagement(webs_t wp, char_t *path, char_t *query)
{
char_t *ok;
a_assert(wp);
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Load Cancelled."));
} else if (umRestore(NULL) != 0) {
websWrite(wp, T("ERROR: Unable to load user configuration."));
} else {
websWrite(wp, T("User configuration was re-loaded successfully."));
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Message start and end convenience functions
*/
static void websMsgStart(webs_t wp)
{
websWrite(wp, MSG_START);
}
static void websMsgEnd(webs_t wp)
{
websWrite(wp, MSG_END);
}
/******************************************************************************/

View File

@@ -1,212 +0,0 @@
/*
* url.c -- Parse URLs
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* This module parses URLs into their components.
*/
/********************************* Includes ***********************************/
#include "wsIntrn.h"
/********************************* Statics ************************************/
/*
* htmExt is declared in this way to avoid a Linux and Solaris segmentation
* fault when a constant string is passed to strlower which could change its
* argument.
*/
char_t htmExt[] = T(".htm");
/*********************************** Code *************************************/
/*
* Return the mime type for the given URL given a URL.
* The caller supplies the buffer to hold the result.
* charCnt is the number of characters the buffer will hold, ascii or UNICODE.
*/
char_t *websUrlType(char_t *url, char_t *buf, int charCnt)
{
sym_t *sp;
char_t *ext, *parsebuf;
a_assert(url && *url);
a_assert(buf && charCnt > 0);
if (url == NULL || *url == '\0') {
gstrcpy(buf, T("text/plain"));
return buf;
}
if (websUrlParse(url, &parsebuf, NULL, NULL, NULL, NULL, NULL,
NULL, &ext) < 0) {
gstrcpy(buf, T("text/plain"));
return buf;
}
strlower(ext);
/*
* Lookup the mime type symbol table to find the relevant content type
*/
if ((sp = symLookup(websMime, ext)) != NULL) {
gstrncpy(buf, sp->content.value.string, charCnt);
} else {
gstrcpy(buf, T("text/plain"));
}
bfree(B_L, parsebuf);
return buf;
}
/******************************************************************************/
/*
* Parse the URL. A buffer is allocated to store the parsed URL in *pbuf.
* This must be freed by the caller. NOTE: tag is not yet fully supported.
*/
int websUrlParse(char_t *url, char_t **pbuf, char_t **phost, char_t **ppath,
char_t **pport, char_t **pquery, char_t **pproto, char_t **ptag,
char_t **pext)
{
char_t *tok, *cp, *host, *path, *port, *proto, *tag, *query, *ext;
char_t *last_delim, *hostbuf, *portbuf, *buf;
int c, len, ulen;
a_assert(url);
a_assert(pbuf);
ulen = gstrlen(url);
/*
* We allocate enough to store separate hostname and port number fields.
* As there are 3 strings in the one buffer, we need room for 3 null chars.
* We allocate MAX_PORT_LEN char_t's for the port number.
*/
len = ulen * 2 + MAX_PORT_LEN + 3;
if ((buf = balloc(B_L, len * sizeof(char_t))) == NULL) {
return -1;
}
portbuf = &buf[len - MAX_PORT_LEN - 1];
hostbuf = &buf[ulen+1];
gstrcpy(buf, url);
url = buf;
/*
* Convert the current listen port to a string. We use this if the URL has
* no explicit port setting
*/
stritoa(websGetPort(), portbuf, MAX_PORT_LEN);
port = portbuf;
path = T("/");
proto = T("http");
host = T("localhost");
query = T("");
ext = htmExt;
tag = T("");
if (gstrncmp(url, T("http://"), 7) == 0) {
tok = &url[7];
tok[-3] = '\0';
proto = url;
host = tok;
for (cp = tok; *cp; cp++) {
if (*cp == '/') {
break;
}
if (*cp == ':') {
*cp++ = '\0';
port = cp;
tok = cp;
}
}
if ((cp = gstrchr(tok, '/')) != NULL) {
/*
* If a full URL is supplied, we need to copy the host and port
* portions into static buffers.
*/
c = *cp;
*cp = '\0';
gstrncpy(hostbuf, host, ulen);
gstrncpy(portbuf, port, MAX_PORT_LEN);
*cp = c;
host = hostbuf;
port = portbuf;
path = cp;
tok = cp;
}
} else {
path = url;
tok = url;
}
/*
* Parse the query string
*/
if ((cp = gstrchr(tok, '?')) != NULL) {
*cp++ = '\0';
query = cp;
path = tok;
tok = query;
}
/*
* Parse the fragment identifier
*/
if ((cp = gstrchr(tok, '#')) != NULL) {
*cp++ = '\0';
if (*query == 0) {
path = tok;
}
}
/*
* Only do the following if asked for the extension
*/
if (pext) {
if ((cp = gstrrchr(path, '.')) != NULL) {
if ((last_delim = gstrrchr(path, '/')) != NULL) {
if (last_delim > cp) {
ext = htmExt;
} else {
ext = cp;
}
} else {
ext = cp;
}
} else {
if (path[gstrlen(path) - 1] == '/') {
ext = htmExt;
}
}
}
/*
* Pass back the fields requested (if not NULL)
*/
if (phost)
*phost = host;
if (ppath)
*ppath = path;
if (pport)
*pport = port;
if (pproto)
*pproto = proto;
if (pquery)
*pquery = query;
if (ptag)
*ptag = tag;
if (pext)
*pext = ext;
*pbuf = buf;
return 0;
}
/******************************************************************************/

File diff suppressed because it is too large Load Diff

View File

@@ -1,149 +0,0 @@
/*
* base64.c -- Base64 Mime encoding
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* The base64 command encodes and decodes a string in mime base64 format
*/
/********************************* Includes ***********************************/
#include "wsIntrn.h"
/******************************** Local Data **********************************/
/*
* Mapping of ANSI chars to base64 Mime encoding alphabet (see below)
*/
static char_t map64[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};
static char_t alphabet64[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/',
};
/*********************************** Code *************************************/
/*
* Decode a buffer from "string" and into "outbuf"
*/
int websDecode64(char_t *outbuf, char_t *string, int outlen)
{
unsigned long shiftbuf;
char_t *cp, *op;
int c, i, j, shift;
op = outbuf;
*op = '\0';
cp = string;
while (*cp && *cp != '=') {
/*
* Map 4 (6bit) input bytes and store in a single long (shiftbuf)
*/
shiftbuf = 0;
shift = 18;
for (i = 0; i < 4 && *cp && *cp != '='; i++, cp++) {
c = map64[*cp & 0xff];
if (c == -1) {
error(E_L, E_LOG, T("Bad string: %s at %c index %d"), string,
c, i);
return -1;
}
shiftbuf = shiftbuf | (c << shift);
shift -= 6;
}
/*
* Interpret as 3 normal 8 bit bytes (fill in reverse order).
* Check for potential buffer overflow before filling.
*/
--i;
if ((op + i) >= &outbuf[outlen]) {
gstrcpy(outbuf, T("String too big"));
return -1;
}
for (j = 0; j < i; j++) {
*op++ = (char_t) ((shiftbuf >> (8 * (2 - j))) & 0xff);
}
*op = '\0';
}
return 0;
}
/******************************************************************************/
/*
* Encode a buffer from "string" into "outbuf"
*/
void websEncode64(char_t *outbuf, char_t *string, int outlen)
{
unsigned long shiftbuf;
char_t *cp, *op;
int x, i, j, shift;
op = outbuf;
*op = '\0';
cp = string;
while (*cp) {
/*
* Take three characters and create a 24 bit number in shiftbuf
*/
shiftbuf = 0;
for (j = 2; j >= 0 && *cp; j--, cp++) {
shiftbuf |= ((*cp & 0xff) << (j * 8));
}
/*
* Now convert shiftbuf to 4 base64 letters. The i,j magic calculates
* how many letters need to be output.
*/
shift = 18;
for (i = ++j; i < 4 && op < &outbuf[outlen] ; i++) {
x = (shiftbuf >> shift) & 0x3f;
*op++ = alphabet64[(shiftbuf >> shift) & 0x3f];
shift -= 6;
}
/*
* Pad at the end with '='
*/
while (j-- > 0) {
*op++ = '=';
}
*op = '\0';
}
}
/******************************************************************************/

View File

@@ -1,188 +0,0 @@
/*
* webcomp -- Compile web pages into C source
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* Usage: webcomp prefix filelist >webrom.c
*
* filelist is a file containing the pathnames of all web pages
* prefix is a path prefix to remove from all the web page pathnames
* webrom.c is the resulting C source file to compile and link.
*/
/********************************* Includes ***********************************/
#include "wsIntrn.h"
/**************************** Forward Declarations ****************************/
static int compile(char_t *fileList, char_t *prefix);
static void usage();
/*********************************** Code *************************************/
/*
* Main program for webpack test harness
*/
int gmain(int argc, char_t* argv[])
{
char_t *fileList, *prefix;
fileList = NULL;
if (argc != 3) {
usage();
}
prefix = argv[1];
fileList = argv[2];
if (compile(fileList, prefix) < 0) {
return -1;
}
return 0;
}
/******************************************************************************/
/*
* Output usage message
*/
static void usage()
{
fprintf(stderr, "usage: webcomp prefix filelist >output.c\n");
exit(2);
}
/******************************************************************************/
/*
* Compile the web pages
*/
static int compile(char_t *fileList, char_t *prefix)
{
gstat_t sbuf;
FILE *lp;
time_t now;
char_t file[FNAMESIZE];
char_t *cp, *sl;
char buf[512];
unsigned char *p;
int j, i, len, fd, nFile;
/*
* Open list of files
*/
if ((lp = fopen(fileList, "r")) == NULL) {
fprintf(stderr, "Can't open file list %s\n", fileList);
return -1;
}
time(&now);
fprintf(stdout, "/*\n * webrom.c -- Compiled Web Pages\n *\n");
fprintf(stdout, " * Compiled by GoAhead WebCompile: %s */\n\n",
gctime(&now));
fprintf(stdout, "#include \"wsIntrn.h\"\n\n");
fprintf(stdout, "#ifndef WEBS_PAGE_ROM\n");
fprintf(stdout, "websRomPageIndexType websRomPageIndex[] = {\n");
fprintf(stdout, " { 0, 0, 0 },\n};\n");
fprintf(stdout, "#else\n");
/*
* Open each input file and compile each web page
*/
nFile = 0;
while (fgets(file, sizeof(file), lp) != NULL) {
if ((p = strchr(file, '\n')) || (p = strchr(file, '\r'))) {
*p = '\0';
}
if (*file == '\0') {
continue;
}
if (gstat(file, &sbuf) == 0 && sbuf.st_mode & S_IFDIR) {
continue;
}
if ((fd = gopen(file, O_RDONLY | O_BINARY)) < 0) {
fprintf(stderr, "Can't open file %s\n", file);
return -1;
}
fprintf(stdout, "static unsigned char page_%d[] = {\n", nFile);
while ((len = read(fd, buf, sizeof(buf))) > 0) {
p = buf;
for (i = 0; i < len; ) {
fprintf(stdout, " ");
for (j = 0; p < &buf[len] && j < 16; j++, p++) {
fprintf(stdout, "%3d,", *p);
}
i += j;
fprintf(stdout, "\n");
}
}
fprintf(stdout, " 0 };\n\n");
close(fd);
nFile++;
}
fclose(lp);
/*
* Now output the page index
*/
fprintf(stdout, "websRomPageIndexType websRomPageIndex[] = {\n");
if ((lp = fopen(fileList, "r")) == NULL) {
fprintf(stderr, "Can't open file list %s\n", fileList);
return -1;
}
nFile = 0;
while (fgets(file, sizeof(file), lp) != NULL) {
if ((p = strchr(file, '\n')) || (p = strchr(file, '\r'))) {
*p = '\0';
}
if (*file == '\0') {
continue;
}
/*
* Remove the prefix and add a leading "/" when we print the path
*/
if (strncmp(file, prefix, gstrlen(prefix)) == 0) {
cp = &file[gstrlen(prefix)];
} else {
cp = file;
}
while((sl = strchr(file, '\\')) != NULL) {
*sl = '/';
}
if (*cp == '/') {
cp++;
}
if (gstat(file, &sbuf) == 0 && sbuf.st_mode & S_IFDIR) {
fprintf(stdout, " { T(\"/%s\"), 0, 0 },\n", cp);
continue;
}
fprintf(stdout, " { T(\"/%s\"), page_%d, %d },\n", cp, nFile,
sbuf.st_size);
nFile++;
}
fclose(lp);
fprintf(stdout, " { 0, 0, 0 },\n");
fprintf(stdout, "};\n");
fprintf(stdout, "#endif /* WEBS_PAGE_ROM */\n");
fclose(lp);
fflush(stdout);
return 0;
}
/******************************************************************************/

View File

@@ -1,499 +0,0 @@
/*
* main.c -- Main program for the GoAhead WebServer (RTEMS version)
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* Main program for for the GoAhead WebServer. This is a demonstration
* main program to initialize and configure the web server.
*/
/********************************* Includes ***********************************/
#include "uemf.h"
#include "wsIntrn.h"
#include <signal.h>
#include <sys/time.h>
#include <pthread.h>
#include <rtems.h>
#include <rtems/error.h>
#ifdef WEBS_SSL_SUPPORT
#include "websSSL.h"
#endif
#ifdef USER_MANAGEMENT_SUPPORT
#include "um.h"
void formDefineUserMgmt(void);
#endif
/*********************************** Locals ***********************************/
/*
* Change configuration here
*/
extern const char *tftpServer;
/* static char_t *rootWeb = T("goahead"); * Root web directory */
static char_t *password = T(""); /* Security password */
static int port = 80; /* Server port */
static int retries = 5; /* Server port retries */
static int finished; /* Finished flag */
/*
* Structure to hold timer events
*/
typedef struct {
void (*routine)(long arg); /* Timer routine */
long arg; /* Argument to routine */
} websTimer_t;
/* The following holds the pointer to an allocated websTimer_t structure .
* Using this method only one timer can be active at a time, but
* for the WebServer, this should be OK.
*/
websTimer_t *tp;
/****************************** Forward Declarations **************************/
static int initWebs();
static int aspTest(int eid, webs_t wp, int argc, char_t **argv);
static void formTest(webs_t wp, char_t *path, char_t *query);
static int websHomePageHandler(webs_t wp, char_t *urlPrefix, char_t *webDir,
int arg, char_t* url, char_t* path, char_t* query);
static void timerProc(int signo);
#if B_STATS
static void printMemStats(int handle, char_t *fmt, ...);
static void memLeaks();
#endif
static timer_t timer_id;
static void rtems_httpd_daemon();
/*********************************** Code *************************************/
/*
* Main -- entry point from RTEMS
*/
int rtems_initialize_webserver()
{
rtems_status_code sc;
rtems_id tid;
int priority;
/***********************************************************************
* Default HTTPD priority.
**********************************************************************/
priority = 40;
sc = rtems_task_create(rtems_build_name('H', 'T', 'P', 'D'),
priority, 8*1024,
RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR |
RTEMS_INTERRUPT_LEVEL(0),
RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
&tid);
if (sc != RTEMS_SUCCESSFUL)
{
return(RTEMS_UNSATISFIED);
}
sc = rtems_task_start(tid, rtems_httpd_daemon, 0);
if (sc != RTEMS_SUCCESSFUL)
{
return(RTEMS_UNSATISFIED);
}
return(RTEMS_SUCCESSFUL);
}
static void
rtems_httpd_daemon()
{
/*
* Initialize the memory allocator. Allow use of malloc and start with a
* 10K heap.
*/
bopen(NULL, (10 * 1024), B_USE_MALLOC);
/*
* Initialize the web server
*/
if (initWebs() < 0) {
rtems_panic("Unable to initialize Web server !!\n");
}
#ifdef WEBS_SSL_SUPPORT
websSSLOpen();
#endif
/*
* Basic event loop. SocketReady returns true when a socket is ready for
* service. SocketSelect will block until an event occurs. SocketProcess
* will actually do the servicing.
*/
while (!finished) {
if (socketReady(-1) || socketSelect(-1, 2000)) {
socketProcess(-1);
}
/*websCgiCleanup();*/
emfSchedProcess();
}
#ifdef WEBS_SSL_SUPPORT
websSSLClose();
#endif
#ifdef USER_MANAGEMENT_SUPPORT
umClose();
#endif
/*
* Close the socket module, report memory leaks and close the memory allocator
*/
websCloseServer();
websDefaultClose();
socketClose();
symSubClose();
#if B_STATS
memLeaks();
#endif
bclose();
rtems_task_delete( RTEMS_SELF );
}
/******************************************************************************/
/*
* Initialize the web server.
*/
static int initWebs()
{
struct hostent* hp;
struct in_addr intaddr;
char host[128], webdir[128];
char_t wbuf[128];
/*
* Initialize the socket subsystem
*/
socketOpen();
/*
* Define the local Ip address, host name, default home page and the
* root web directory.
*/
if (gethostname(host, sizeof(host)) < 0) {
error(E_L, E_LOG, T("Can't get hostname"));
return -1;
}
/* intaddr.s_addr = (unsigned long) hostGetByName(host); */
if ((hp = gethostbyname(host)) == NULL) {
error(E_L, E_LOG, T("Can't get host address"));
return -1;
}
memcpy((char *) &intaddr, (char *) hp->h_addr_list[0],
(size_t) hp->h_length);
#if 0
/*
* Set /TFTP/x.y.z.w/goahead as the root web. Modify to suit your needs
*/
sprintf(webdir, "/TFTP/%s/%s", tftpServer, rootWeb);
#else
sprintf(webdir, "/");
#endif
/*
* Configure the web server options before opening the web server
*/
websSetDefaultDir(webdir);
ascToUni(wbuf, inet_ntoa(intaddr), sizeof(wbuf));
websSetIpaddr(wbuf);
ascToUni(wbuf, host, sizeof(wbuf));
websSetHost(wbuf);
/*
* Configure the web server options before opening the web server
*/
#if 0
websSetDefaultPage(T("default.asp"));
#else
websSetDefaultPage(T("index.html"));
#endif
websSetPassword(password);
/*
* Open the web server on the given port. If that port is taken, try
* the next sequential port for up to "retries" attempts.
*/
websOpenServer(port, retries);
/*
* First create the URL handlers. Note: handlers are called in sorted order
* with the longest path handler examined first. Here we define the security
* handler, forms handler and the default web page handler.
*/
websUrlHandlerDefine(T(""), NULL, 0, websSecurityHandler,
WEBS_HANDLER_FIRST);
websUrlHandlerDefine(T("/goform"), NULL, 0, websFormHandler, 0);
websUrlHandlerDefine(T(""), NULL, 0, websDefaultHandler,
WEBS_HANDLER_LAST);
/*
* Now define two test procedures. Replace these with your application
* relevant ASP script procedures and form functions.
*/
websAspDefine(T("aspTest"), aspTest);
websFormDefine(T("formTest"), formTest);
/*
* Create a handler for the default home page
*/
websUrlHandlerDefine(T("/"), NULL, 0, websHomePageHandler, 0);
return 0;
}
/******************************************************************************/
/*
* Test Javascript binding for ASP. This will be invoked when "aspTest" is
* embedded in an ASP page. See web/asp.asp for usage. Set browser to
* "localhost/asp.asp" to test.
*/
static int aspTest(int eid, webs_t wp, int argc, char_t **argv)
{
char_t *name, *address;
if (ejArgs(argc, argv, T("%s %s"), &name, &address) < 2) {
websError(wp, 400, T("Insufficient args\n"));
return -1;
}
return websWrite(wp, T("Name: %s, Address %s"), name, address);
}
/******************************************************************************/
/*
* Test form for posted data (in-memory CGI). This will be called when the
* form in web/asp.asp is invoked. Set browser to "localhost/asp.asp" to test.
*/
static void formTest(webs_t wp, char_t *path, char_t *query)
{
char_t *name, *address;
name = websGetVar(wp, T("name"), T("Joe Smith"));
address = websGetVar(wp, T("address"), T("1212 Milky Way Ave."));
websHeader(wp);
websWrite(wp, T("<body><h2>Name: %s, Address: %s</h2>\n"), name, address);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Create a timer to invoke the routine in "delay" milliseconds.
*/
void *emfCreateTimer(int delay, void (*routine)(long arg), long arg)
{
/* this variable is only used in the if'ed 0 section below */
#if 0
struct sigaction act;
#endif
struct itimerspec its = { {0,0}, {0,0} };
struct sigevent se;
int status;
if ((tp = balloc(B_L, sizeof(websTimer_t)))) {
tp->routine = routine;
tp->arg = arg;
}
else {
return NULL;
}
se.sigev_notify = SIGEV_THREAD;
se.sigev_value.sival_ptr = tp;
se.sigev_notify_function = (void (*)(union sigval)) timerProc;
/*
* NOT POSIX?
* se.sigev_notify_attributes = NULL;
*/
status = timer_create(CLOCK_REALTIME, &se, &timer_id);
if (status != 0) {
bfree(B_L, tp);
return NULL;
}
/* convert delay millisecs to secs and usecs required by struct */
its.it_value.tv_sec = delay / 1000;
its.it_value.tv_nsec = (delay % 1000) * 1000000;
status = timer_settime(timer_id, 0, &its, 0);
if (status != 0) {
bfree(B_L, tp);
return NULL;
}
#if 0
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
act.sa_handler = timerProc;
sigaction(SIGALRM, &act, NULL);
/* convert delay millisecs to secs and usecs required by struct */
its.it_value.tv_sec = delay / 1000;
its.it_value.tv_usec = (delay % 1000) * 1000;
if (setitimer(ITIMER_REAL, &its, NULL) == -1) {
bfree(B_L, tp);
return NULL;
}
#endif
return tp;
}
/******************************************************************************/
/*
* Delete a timer
*/
void emfDeleteTimer(void * id)
{
websTimer_t *wtp;
/*struct itimerval its = { {0,0}, {0,0} };*/
wtp = (websTimer_t *)id;
/* setitimer(ITIMER_REAL, &its, NULL);*/
timer_delete(timer_id);
bfree(B_L, wtp);
}
/******************************************************************************/
/*
* Timer handler
*/
static void timerProc(int signo)
{
websTimer_t wtp = *tp;
/* Copy the timer structure to a local first and delete it before calling
* the function, since the function could create another timer. In this
* implementation, only one timer can be allocated at a time.
*/
bfree(B_L, tp);
(wtp.routine)(wtp.arg);
}
/******************************************************************************/
/*
* Home page handler
*/
static int websHomePageHandler(webs_t wp, char_t *urlPrefix, char_t *webDir,
int arg, char_t* url, char_t* path, char_t* query)
{
/*
* If the empty or "/" URL is invoked, redirect default URLs to the home page
*/
if (*url == '\0' || gstrcmp(url, T("/")) == 0) {
#if 0
websRedirect(wp, T("home.asp"));
#else
websRedirect(wp, T("index.html"));
#endif
return 1;
}
return 0;
}
/******************************************************************************/
#if B_STATS
static void memLeaks()
{
int fd=1;
/* if ((fd = gopen(T("leak.txt"), O_CREAT | O_TRUNC | O_WRONLY)) >= 0) { */
bstats(fd, printMemStats);
/*
close(fd);
}
*/
}
/******************************************************************************/
/*
* Print memory usage / leaks
*/
static void printMemStats(int handle, char_t *fmt, ...)
{
va_list args;
char_t buf[256];
va_start(args, fmt);
vsprintf(buf, fmt, args);
va_end(args);
write(handle, buf, strlen(buf));
}
#endif
/*****************************************************************************/
/*****************************************************************************/
/*
* Default error handler. The developer should insert code to handle
* error messages in the desired manner.
*/
void defaultErrorHandler(int etype, char_t *msg)
{
#if 1
write(1, msg, gstrlen(msg));
#endif
}
/*****************************************************************************/
/*
* Trace log. Customize this function to log trace output
*/
void defaultTraceHandler(int level, char_t *buf)
{
/*
* The following code would write all trace regardless of level
* to stdout.
*/
#if 1
if (buf) {
write(1, buf, gstrlen(buf));
}
#endif
}
/*****************************************************************************/
/*
* Returns a pointer to an allocated qualified unique temporary file name.
* This filename must eventually be deleted with bfree();
*/
char_t *websGetCgiCommName()
{
char_t *pname1, *pname2;
pname1 = tempnam(NULL, T("cgi"));
pname2 = bstrdup(B_L, pname1);
free(pname1);
return pname2;
}

View File

@@ -1,141 +0,0 @@
/*
* Page.c -- Support for page retrieval.
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* This module provides page retrieval handling. It provides support for
* reading web pages from file systems and has expansion for ROMed web
* pages.
*/
/********************************* Includes ***********************************/
#include "wsIntrn.h"
/*********************************** Code *************************************/
/*
* Open a web page. lpath is the local filename. path is the URL path name.
*/
int websPageOpen(webs_t wp, char_t *lpath, char_t *path, int mode, int perm)
{
a_assert(websValid(wp));
#ifdef WEBS_PAGE_ROM
return websRomPageOpen(wp, path, mode, perm);
#else
return (wp->docfd = gopen(lpath, mode, perm));
#endif /* WEBS_PAGE_ROM */
}
/******************************************************************************/
/*
* Close a web page
*/
void websPageClose(webs_t wp)
{
a_assert(websValid(wp));
#ifdef WEBS_PAGE_ROM
websRomPageClose(wp->docfd);
#else
if (wp->docfd >= 0) {
close(wp->docfd);
wp->docfd = -1;
}
#endif
}
/******************************************************************************/
/*
* Stat a web page lpath is the local filename. path is the URL path name.
*/
int websPageStat(webs_t wp, char_t *lpath, char_t *path, websStatType* sbuf)
{
#ifdef WEBS_PAGE_ROM
return websRomPageStat(path, sbuf);
#else
gstat_t s;
if (gstat(lpath, &s) < 0) {
return -1;
}
sbuf->size = s.st_size;
sbuf->mtime = s.st_mtime;
sbuf->isDir = s.st_mode & S_IFDIR;
return 0;
#endif
}
/******************************************************************************/
/*
* Is this file a directory?
*/
int websPageIsDirectory(char_t *lpath)
{
#ifdef WEBS_PAGE_ROM
websStatType sbuf;
if (websRomPageStat(lpath, &sbuf) >= 0) {
return(sbuf.isDir);
} else {
return 0;
}
#else
gstat_t sbuf;
if (gstat(lpath, &sbuf) >= 0) {
return(sbuf.st_mode & S_IFDIR);
} else {
return 0;
}
#endif
}
/******************************************************************************/
/*
* Read a web page. Returns the number of _bytes_ read.
* len is the size of buf, in bytes.
*/
int websPageReadData(webs_t wp, char *buf, int nBytes)
{
#ifdef WEBS_PAGE_ROM
a_assert(websValid(wp));
return websRomPageReadData(wp, buf, nBytes);
#else
a_assert(websValid(wp));
return read(wp->docfd, buf, nBytes);
#endif
}
/******************************************************************************/
/*
* Move file pointer offset bytes.
*/
void websPageSeek(webs_t wp, long offset)
{
a_assert(websValid(wp));
#ifdef WEBS_PAGE_ROM
websRomPageSeek(wp, offset, SEEK_CUR);
#else
lseek(wp->docfd, offset, SEEK_CUR);
#endif
}
/******************************************************************************/

View File

@@ -1,15 +0,0 @@
/*
* webrom.c -- Compiled Web Pages
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
#include "wsIntrn.h"
websRomPageIndexType websRomPageIndex[] = {
{ 0, 0, 0 },
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,233 +0,0 @@
/*
* webs.h -- GoAhead Web public header
*
* Copyright (c) GoAhead Software Inc., 1992-2000. All Rights Reserved.
*
* See the file "license.txt" for information on usage and redistribution
*
* $Id$
*/
#ifndef _h_WEBS
#define _h_WEBS 1
/******************************** Description *********************************/
/*
* GoAhead Web Server header. This defines the Web public APIs.
* Include this header for files that contain ASP or Form procedures.
* Include wsIntrn.h when creating URL handlers.
*/
/********************************* Includes ***********************************/
#include "ej.h"
#ifdef WEBS_SSL_SUPPORT
#include "websSSL.h"
#endif
/********************************** Defines ***********************************/
/*
* By license terms the server software name defined in the following line of
* code must not be modified.
*/
#define WEBS_NAME T("GoAhead-Webs")
#define WEBS_VERSION T("2.1.3")
#define WEBS_HEADER_BUFINC 512 /* Header buffer size */
#define WEBS_ASP_BUFINC 512 /* Asp expansion increment */
#define WEBS_MAX_PASS 32 /* Size of password */
#define WEBS_BUFSIZE 1000 /* websWrite max output string */
#define WEBS_MAX_HEADER (5 * 1024) /* Sanity check header */
#define WEBS_MAX_URL 4096 /* Maximum URL size for sanity */
#define WEBS_SOCKET_BUFSIZ 256 /* Bytes read from socket */
#define WEBS_HTTP_PORT T("httpPort")
#define CGI_BIN T("cgi-bin")
/*
* Request flags. Also returned by websGetRequestFlags().
*/
#define WEBS_LOCAL_PAGE 0x1 /* Request for local webs page */
#define WEBS_KEEP_ALIVE 0x2 /* HTTP/1.1 keep alive */
#define WEBS_DONT_USE_CACHE 0x4 /* Not implemented cache support */
#define WEBS_COOKIE 0x8 /* Cookie supplied in request */
#define WEBS_IF_MODIFIED 0x10 /* If-modified-since in request */
#define WEBS_POST_REQUEST 0x20 /* Post request operation */
#define WEBS_LOCAL_REQUEST 0x40 /* Request from this system */
#define WEBS_HOME_PAGE 0x80 /* Request for the home page */
#define WEBS_ASP 0x100 /* ASP request */
#define WEBS_HEAD_REQUEST 0x200 /* Head request */
#define WEBS_CLEN 0x400 /* Request had a content length */
#define WEBS_FORM 0x800 /* Request is a form */
#define WEBS_REQUEST_DONE 0x1000 /* Request complete */
#define WEBS_POST_DATA 0x2000 /* Already appended post data */
#define WEBS_CGI_REQUEST 0x4000 /* cgi-bin request */
#define WEBS_SECURE 0x8000 /* connection uses SSL */
#define WEBS_AUTH_BASIC 0x10000 /* Basic authentication request */
#define WEBS_AUTH_DIGEST 0x20000 /* Digest authentication request */
#define WEBS_HEADER_DONE 0x40000 /* Already output the HTTP header */
/*
* URL handler flags
*/
#define WEBS_HANDLER_FIRST 0x1 /* Process this handler first */
#define WEBS_HANDLER_LAST 0x2 /* Process this handler last */
/*
* Per socket connection webs structure
*/
typedef struct websRec {
ringq_t header; /* Header dynamic string */
time_t since; /* Parsed if-modified-since time */
sym_fd_t cgiVars; /* CGI standard variables */
sym_fd_t cgiQuery; /* CGI decoded query string */
time_t timestamp; /* Last transaction with browser */
int timeout; /* Timeout handle */
char_t ipaddr[32]; /* Connecting ipaddress */
char_t type[64]; /* Mime type */
char_t *dir; /* Directory containing the page */
char_t *path; /* Path name without query */
char_t *url; /* Full request url */
char_t *host; /* Requested host */
char_t *lpath; /* Cache local path name */
char_t *query; /* Request query */
char_t *decodedQuery; /* Decoded request query */
char_t *authType; /* Authorization type (Basic/DAA) */
char_t *password; /* Authorization password */
char_t *userName; /* Authorization username */
char_t *cookie; /* Cookie string */
char_t *userAgent; /* User agent (browser) */
char_t *protocol; /* Protocol (normally HTTP) */
char_t *protoVersion; /* Protocol version */
int sid; /* Socket id (handler) */
int listenSid; /* Listen Socket id */
int port; /* Request port number */
int state; /* Current state */
int flags; /* Current flags -- see above */
int code; /* Request result code */
int clen; /* Content length */
int wid; /* Index into webs */
char_t *cgiStdin; /* filename for CGI stdin */
int docfd; /* Document file descriptor */
int numbytes; /* Bytes to transfer to browser */
int written; /* Bytes actually transferred */
void (*writeSocket)(struct websRec *wp);
#ifdef DIGEST_ACCESS_SUPPORT
char_t *realm; /* usually the same as "host" from websRec */
char_t *nonce; /* opaque-to-client string sent by server */
char_t *digest; /* digest form of user password */
char_t *uri; /* URI found in DAA header */
char_t *opaque; /* opaque value passed from server */
char_t *nc; /* nonce count */
char_t *cnonce; /* check nonce */
char_t *qop; /* quality operator */
#endif
#ifdef WEBS_SSL_SUPPORT
websSSL_t *wsp; /* SSL data structure */
#endif
} websRec;
typedef websRec *webs_t;
typedef websRec websType;
/******************************** Prototypes **********************************/
extern int websAccept(int sid, char *ipaddr, int port, int listenSid);
extern int websAspDefine(char_t *name,
int (*fn)(int ejid, webs_t wp, int argc, char_t **argv));
extern int websAspRequest(webs_t wp, char_t *lpath);
extern void websCloseListen();
extern int websDecode64(char_t *outbuf, char_t *string, int buflen);
extern void websDecodeUrl(char_t *token, char_t *decoded, int len);
extern void websDone(webs_t wp, int code);
extern void websEncode64(char_t *outbuf, char_t *string, int buflen);
extern void websError(webs_t wp, int code, char_t *msg, ...);
/* function websErrorMsg() made extern 03 Jun 02 BgP */
extern char_t *websErrorMsg(int code);
extern void websFooter(webs_t wp);
extern int websFormDefine(char_t *name, void (*fn)(webs_t wp,
char_t *path, char_t *query));
extern char_t *websGetDefaultDir();
extern char_t *websGetDefaultPage();
extern char_t *websGetHostUrl();
extern char_t *websGetIpaddrUrl();
extern char_t *websGetPassword();
extern int websGetPort();
extern char_t *websGetPublishDir(char_t *path, char_t **urlPrefix);
extern char_t *websGetRealm();
extern int websGetRequestBytes(webs_t wp);
extern char_t *websGetRequestDir(webs_t wp);
extern int websGetRequestFlags(webs_t wp);
extern char_t *websGetRequestIpaddr(webs_t wp);
extern char_t *websGetRequestLpath(webs_t wp);
extern char_t *websGetRequestPath(webs_t wp);
extern char_t *websGetRequestPassword(webs_t wp);
extern char_t *websGetRequestType(webs_t wp);
extern int websGetRequestWritten(webs_t wp);
extern char_t *websGetVar(webs_t wp, char_t *var, char_t *def);
extern int websCompareVar(webs_t wp, char_t *var, char_t *value);
extern void websHeader(webs_t wp);
extern int websOpenListen(int port, int retries);
extern int websPageOpen(webs_t wp, char_t *lpath, char_t *path,
int mode, int perm);
extern void websPageClose(webs_t wp);
extern int websPublish(char_t *urlPrefix, char_t *path);
extern void websRedirect(webs_t wp, char_t *url);
extern void websSecurityDelete();
extern int websSecurityHandler(webs_t wp, char_t *urlPrefix,
char_t *webDir, int arg, char_t *url, char_t *path,
char_t *query);
extern void websSetDefaultDir(char_t *dir);
extern void websSetDefaultPage(char_t *page);
extern void websSetEnv(webs_t wp);
extern void websSetHost(char_t *host);
extern void websSetIpaddr(char_t *ipaddr);
extern void websSetPassword(char_t *password);
extern void websSetRealm(char_t *realmName);
extern void websSetRequestBytes(webs_t wp, int bytes);
extern void websSetRequestFlags(webs_t wp, int flags);
extern void websSetRequestLpath(webs_t wp, char_t *lpath);
extern void websSetRequestPath(webs_t wp, char_t *dir, char_t *path);
extern char_t *websGetRequestUserName(webs_t wp);
extern void websSetRequestWritten(webs_t wp, int written);
extern void websSetVar(webs_t wp, char_t *var, char_t *value);
extern int websTestVar(webs_t wp, char_t *var);
extern void websTimeoutCancel(webs_t wp);
extern int websUrlHandlerDefine(char_t *urlPrefix, char_t *webDir,
int arg, int (*fn)(webs_t wp, char_t *urlPrefix,
char_t *webDir, int arg, char_t *url, char_t *path,
char_t *query), int flags);
extern int websUrlHandlerDelete(int (*fn)(webs_t wp, char_t *urlPrefix,
char_t *webDir, int arg, char_t *url, char_t *path,
char_t *query));
extern int websUrlHandlerRequest(webs_t wp);
extern int websUrlParse(char_t *url, char_t **buf, char_t **host,
char_t **path, char_t **port, char_t **query,
char_t **proto, char_t **tag, char_t **ext);
extern char_t *websUrlType(char_t *webs, char_t *buf, int charCnt);
extern int websWrite(webs_t wp, char_t* fmt, ...);
extern int websWriteBlock(webs_t wp, char_t *buf, int nChars);
extern int websWriteDataNonBlock(webs_t wp, char *buf, int nChars);
extern int websValid(webs_t wp);
extern int websValidateUrl(webs_t wp, char_t *path);
extern void websSetTimeMark(webs_t wp);
/*
* The following prototypes are used by the SSL patch found in websSSL.c
*/
extern int websAlloc(int sid);
extern void websFree(webs_t wp);
extern void websTimeout(void *arg, int id);
extern void websReadEvent(webs_t wp);
/*
* Prototypes for functions available when running as part of the
* GoAhead Embedded Management Framework (EMF)
*/
#ifdef EMF
extern void websFormExplain(webs_t wp, char_t *path, char_t *query);
#endif
#endif /* _h_WEBS */
/******************************************************************************/

View File

@@ -1,706 +0,0 @@
/*
* websSSL.c -- SSL envrionment creation
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* This module implements a patch into SSL implementations for the webs
* module.
*/
/********************************* Includes ***********************************/
#include "wsIntrn.h"
#include "webs.h"
#include "websSSL.h"
/******************************* Definitions **********************************/
#define DEFAULT_CERT_FILE "./server.pem"
#define DEFAULT_KEY_FILE "./certs/cakey.pem"
#define DEFAULT_CA_FILE "./certs/cacert.pem"
#define DEFAULT_CA_PATH "./certs/"
#define SSL_PORT 443
/*
* Define the components of the apps_startup() macro
*/
#ifdef SIGPIPE
#define do_pipe_sig() signal(SIGPIPE,SIG_IGN)
#else
#define do_pipe_sig()
#endif
#ifdef OPENSSL
#define SSLC_add_all_algorithms() SSLeay_add_all_algorithms()
#else
extern void SSLC_add_all_algorithms(void);
#endif
/*
* Define the apps_startup() macro
*/
# if defined(MSDOS) || defined(WIN16) || defined(WIN32)
# ifdef _O_BINARY
# define apps_startup() \
_fmode=_O_BINARY; do_pipe_sig(); CRYPTO_malloc_init(); \
SSLC_add_all_algorithms()
# else
# define apps_startup() \
_fmode=O_BINARY; do_pipe_sig(); CRYPTO_malloc_init(); \
SSLC_add_all_algorithms()
# endif
# else
# define apps_startup() do_pipe_sig(); SSLC_add_all_algorithms();
# endif
/*************************** Forward Declarations *****************************/
static int websSSLSetCertStuff(SSL_CTX *ctx,
char *cert_file,
char *key_file);
static int websSSLVerifyCallback(int ok, X509_STORE_CTX *ctx);
static RSA *websSSLTempRSACallback(SSL *s, int is_export, int keylength);
static int websSSLReadEvent (webs_t wp);
static int websSSLAccept(int sid, char *ipaddr, int port, int listenSid);
static void websSSLSocketEvent(int sid, int mask, int data);
/*********************************** Locals ***********************************/
static int sslListenSock = -1; /* Listen socket */
static SSL_CTX *sslctx = NULL;
/******************************************************************************/
/*
* Start up the SSL Context for the application, and start a listen on the
* SSL port (usually 443, and defined by SSL_PORT)
* Return 0 on success, -1 on failure.
*/
int websSSLOpen()
{
char *certFile, *keyFile, *CApath, *CAfile;
SSL_METHOD *meth;
/*
* Install and initialize the SSL library
*/
apps_startup();
trace(7, T("SSL: Initializing SSL\n"));
#ifdef SSLC
SSL_library_init();
#endif
SSL_load_error_strings();
#ifdef OPENSSL
SSLeay_add_ssl_algorithms();
#endif
/*
* Important! Enable both SSL versions 2 and 3
*/
meth = SSLv23_server_method();
sslctx = SSL_CTX_new(meth);
a_assert(sslctx);
if (sslctx == NULL) {
trace(2, T("SSL: Unable to create SSL context!\n"));
return -1;
}
/*
* Adjust some SSL Context variables
*/
SSL_CTX_set_quiet_shutdown(sslctx, 1);
SSL_CTX_set_options(sslctx, 0);
SSL_CTX_sess_set_cache_size(sslctx, 128);
/*
* Set the certificate verification locations
*/
CApath = DEFAULT_CA_PATH;
CAfile = DEFAULT_CA_FILE;
if ((!SSL_CTX_load_verify_locations(sslctx, CAfile, CApath)) ||
(!SSL_CTX_set_default_verify_paths(sslctx))) {
trace(2, T("SSL: Unable to set cert verification locations!\n"));
websSSLClose();
return -1;
}
/*
* Set the certificate and key files for the SSL context
*/
certFile = DEFAULT_CERT_FILE;
keyFile = NULL;
if (websSSLSetCertStuff(sslctx, certFile, keyFile) != 0) {
websSSLClose();
return -1;
}
/*
* Set the RSA callback for the SSL context
*/
SSL_CTX_set_tmp_rsa_callback(sslctx, websSSLTempRSACallback);
/*
* Set the verification callback for the SSL context
*/
SSL_CTX_set_verify(sslctx, SSL_VERIFY_NONE, websSSLVerifyCallback);
/*
* Set the certificate authority list for the client
*/
SSL_CTX_set_client_CA_list(sslctx, SSL_load_client_CA_file(CAfile));
/*
* Open the socket
*/
sslListenSock = socketOpenConnection(NULL, SSL_PORT,
websSSLAccept, SOCKET_BLOCK);
if (sslListenSock < 0) {
trace(2, T("SSL: Unable to open SSL socket on port <%d>!\n"),
SSL_PORT);
return -1;
}
return 0;
}
/******************************************************************************/
/*
* Return TRUE if websSSL has been opened
*/
int websSSLIsOpen()
{
return (sslListenSock != -1);
}
/******************************************************************************/
/*
* Stops the SSL
*/
void websSSLClose()
{
trace(7, T("SSL: Closing SSL\n"));
if (sslctx != NULL) {
SSL_CTX_free(sslctx);
sslctx = NULL;
}
if (sslListenSock != -1) {
socketCloseConnection(sslListenSock);
sslListenSock = -1;
}
#ifdef SSLC
SSL_library_cleanup();
#endif
}
/******************************************************************************/
/*
* Accept a connection
*/
int websSSLAccept(int sid, char *ipaddr, int port, int listenSid)
{
webs_t wp;
int wid;
a_assert(ipaddr && *ipaddr);
a_assert(sid >= 0);
a_assert(port >= 0);
/*
* Allocate a new handle for this accepted connection. This will allocate
* a webs_t structure in the webs[] list
*/
if ((wid = websAlloc(sid)) < 0) {
return -1;
}
wp = webs[wid];
a_assert(wp);
wp->listenSid = listenSid;
ascToUni(wp->ipaddr, ipaddr, min(sizeof(wp->ipaddr), strlen(ipaddr)+1));
/*
* Check if this is a request from a browser on this system. This is useful
* to know for permitting administrative operations only for local access
*/
if (gstrcmp(wp->ipaddr, T("127.0.0.1")) == 0 ||
gstrcmp(wp->ipaddr, websIpaddr) == 0 ||
gstrcmp(wp->ipaddr, websHost) == 0) {
wp->flags |= WEBS_LOCAL_REQUEST;
}
/*
* Since the acceptance came in on this channel, it must be secure
*/
wp->flags |= WEBS_SECURE;
/*
* Arrange for websSocketEvent to be called when read data is available
*/
socketCreateHandler(sid, SOCKET_READABLE, websSSLSocketEvent, (int) wp);
/*
* Arrange for a timeout to kill hung requests
*/
wp->timeout = emfSchedCallback(WEBS_TIMEOUT, websTimeout, (void *) wp);
trace(8, T("webs: accept request\n"));
return 0;
}
/******************************************************************************/
/*
* The webs socket handler. Called in response to I/O. We just pass control
* to the relevant read or write handler. A pointer to the webs structure
* is passed as an (int) in iwp.
*/
static void websSSLSocketEvent(int sid, int mask, int iwp)
{
webs_t wp;
wp = (webs_t) iwp;
a_assert(wp);
if (! websValid(wp)) {
return;
}
if (mask & SOCKET_READABLE) {
websSSLReadEvent(wp);
}
if (mask & SOCKET_WRITABLE) {
if (wp->writeSocket) {
(*wp->writeSocket)(wp);
}
}
}
/******************************************************************************/
/*
* Handler for SSL Read Events
*/
static int websSSLReadEvent (webs_t wp)
{
int ret, sock;
socket_t *sptr;
SSL *ssl;
BIO *bio, *bioSSL, *bioSock;
#ifdef DEV
const char *ciphers;
#endif
a_assert (wp);
a_assert(websValid(wp));
sptr = socketPtr(wp->sid);
a_assert(sptr);
sock = sptr->sock;
/*
* Create a new BIO and SSL session for this web request
*/
bio = BIO_new(BIO_f_buffer());
a_assert(bio);
if (!BIO_set_write_buffer_size(bio, 128)) {
return -1;
}
ssl = (SSL *) SSL_new(sslctx);
a_assert(ssl);
if (ssl == NULL) {
return -1;
}
SSL_set_session(ssl, NULL);
bioSSL = BIO_new(BIO_f_ssl());
a_assert(bioSSL);
bioSock = BIO_new_socket(sock, BIO_NOCLOSE);
a_assert(bioSock);
SSL_set_bio(ssl, bioSock, bioSock);
SSL_set_accept_state(ssl);
ret = BIO_set_ssl(bioSSL, ssl, BIO_CLOSE);
BIO_push(bio, bioSSL);
#ifdef DEV
ciphers = SSL_get_cipher_list(ssl, 10);
#endif
/*
* Create the SSL data structure in the wp.
*/
#ifdef WEBS_SSL_SUPPORT
wp->wsp = balloc(B_L, sizeof(websSSL_t));
a_assert (wp->wsp);
(wp->wsp)->bio = bio;
(wp->wsp)->ssl = ssl;
#endif
/*
* Call the default Read Event
*/
websReadEvent(wp);
return ret;
}
/******************************************************************************/
/*
* SSL Verification Callback
*/
static int sslVerifyDepth = 0;
static int sslVerifyError = X509_V_OK;
int websSSLVerifyCallback(int ok, X509_STORE_CTX *ctx)
{
char buf[256];
X509 *errCert;
int err;
int depth;
errCert = X509_STORE_CTX_get_current_cert(ctx);
err = X509_STORE_CTX_get_error(ctx);
depth = X509_STORE_CTX_get_error_depth(ctx);
X509_NAME_oneline(X509_get_subject_name(errCert), buf, 256);
if (!ok) {
if (sslVerifyDepth >= depth) {
ok = 1;
sslVerifyError = X509_V_OK;
} else {
ok=0;
sslVerifyError = X509_V_ERR_CERT_CHAIN_TOO_LONG;
}
}
switch (err) {
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
#ifdef OPENSSL
X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
#endif
break;
case X509_V_ERR_CERT_NOT_YET_VALID:
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
case X509_V_ERR_CERT_HAS_EXPIRED:
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
break;
}
return ok;
}
/******************************************************************************/
/*
* Set the SSL certificate and key for the SSL context
*/
int websSSLSetCertStuff(SSL_CTX *ctx, char *certFile, char *keyFile)
{
a_assert (ctx);
a_assert (certFile);
if (certFile != NULL) {
if (SSL_CTX_use_certificate_file(ctx, certFile,
SSL_FILETYPE_PEM) <= 0) {
trace(2, T("SSL: Unable to set certificate file <%s>\n"),
certFile);
return -1;
}
if (keyFile == NULL) {
keyFile = certFile;
}
if (SSL_CTX_use_PrivateKey_file(ctx, keyFile, SSL_FILETYPE_PEM) <= 0) {
trace(2, T("SSL: Unable to set private key file <%s>\n"),
keyFile);
return -1;
}
/*
* Now we know that a key and cert have been set against
* the SSL context
*/
if (!SSL_CTX_check_private_key(ctx)) {
trace(2, T("SSL: Check of private key file <%s> FAILED!\n"),
keyFile);
return -1;
}
}
return 0;
}
/******************************************************************************/
/*
* Set certificate file for SSL context
*/
int websSSLSetCertFile(char_t *certFile)
{
a_assert (sslctx);
a_assert (certFile);
if (sslctx == NULL) {
return -1;
}
if (SSL_CTX_use_certificate_file(sslctx, certFile,
SSL_FILETYPE_PEM) <= 0) {
return -1;
}
/*
* Confirm that the certificate and the private key jive.
*/
if (!SSL_CTX_check_private_key(sslctx)) {
return -1;
}
return 0;
}
/******************************************************************************/
/*
* Set key file for SSL context
*/
int websSSLSetKeyFile(char_t *keyFile)
{
a_assert (sslctx);
a_assert (keyFile);
if (sslctx == NULL) {
return -1;
}
if (SSL_CTX_use_PrivateKey_file(sslctx, keyFile, SSL_FILETYPE_PEM) <= 0) {
return -1;
}
/*
* Confirm that the certificate and the private key jive.
*/
if (!SSL_CTX_check_private_key(sslctx)) {
return -1;
}
return 0;
}
#ifdef SSLC
extern RSA *RSA_new(void);
#endif
/******************************************************************************/
/*
* the Temporary RSA callback
*/
static RSA *websSSLTempRSACallback(SSL *ssl, int isExport, int keyLength)
{
static RSA *rsaTemp = NULL;
if (rsaTemp == NULL) {
#ifdef OPENSSL
rsaTemp = RSA_generate_key(keyLength, RSA_F4, NULL, NULL);
#endif
#ifdef SSLC
rsaTemp = RSA_new();
#endif
}
return rsaTemp;
}
/******************************************************************************/
/*
* Free SSL resources
*/
int websSSLFree(websSSL_t *wsp)
{
if (wsp == NULL) {
return -1;
}
/*
* Make sure we re-use sessions
*/
if (wsp->ssl != NULL) {
SSL_set_shutdown(wsp->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
}
if (wsp->bio != NULL) {
BIO_free_all(wsp->bio);
}
bfree(B_L, wsp);
return 0;
}
/******************************************************************************/
/*
* Return Eof for the SSL BIO
*/
int websSSLEof(websSSL_t *wsp)
{
a_assert(wsp);
if ((wsp == NULL) || (wsp->bio == NULL)) {
return -1;
}
return BIO_eof(wsp->bio);
}
/******************************************************************************/
/*
* Perform a read of the SSL BIO
*/
int websSSLRead(websSSL_t *wsp, char_t *buf, int len)
{
a_assert(wsp);
a_assert(buf);
if ((wsp == NULL) || (wsp->bio == NULL)) {
return -1;
}
return BIO_read(wsp->bio, buf, len);
}
/******************************************************************************/
/*
* Perform a gets of the SSL BIO, returning an balloc'ed string
*/
#define BUF_BLOCK 256
int websSSLGets(websSSL_t *wsp, char_t **buf)
{
int rc, len, lenBuf;
char c;
a_assert(wsp);
a_assert(buf);
lenBuf = 0;
len = 0;
if ((wsp == NULL) || (wsp->bio == NULL)) {
return -1;
}
while (1) {
if ((rc = BIO_read(wsp->bio, &c, 1)) < 0) {
return rc;
}
if (rc == 0) {
/*
* If there is a partial line and we are at EOF, pretend we saw a '\n'
*/
if (len > 0 && BIO_eof(wsp->bio)) {
c = '\n';
} else {
return -1;
}
}
/*
* If a newline is seen, return the data excluding the new line to the
* caller. If carriage return is seen, just eat it.
*/
if (c == '\n') {
if ((len > 0) && (len < lenBuf)) {
(*buf)[len] = 0;
}
return len;
} else if (c == '\r') {
continue;
}
/*
* Append character to buf
*/
if (len >= lenBuf) {
lenBuf += BUF_BLOCK;
*buf = brealloc(B_L, *buf, lenBuf);
}
a_assert(*buf);
(*buf)[len] = c;
len++;
}
}
/******************************************************************************/
/*
* Perform a write to the SSL BIO
*/
int websSSLWrite(websSSL_t *wsp, char_t *buf, int len)
{
a_assert(wsp);
a_assert(buf);
if ((wsp == NULL) || (wsp->bio == NULL)) {
return -1;
}
return BIO_write(wsp->bio, buf, len);
}
/******************************************************************************/
/*
* Perform a flush of the SSL BIO
*/
int websSSLFlush(websSSL_t *wsp)
{
a_assert(wsp);
if ((wsp == NULL) || (wsp->bio == NULL)) {
return -1;
}
return BIO_flush(wsp->bio);
}
/******************************************************************************/

View File

@@ -1,67 +0,0 @@
/*
* websSSL.h -- SSL Patch header
*
* Copyright (c) GoAhead Software Inc., 1992-2000. All Rights Reserved.
*
* See the file "license.txt" for information on usage and redistribution
*
* $Id$
*/
#ifndef _h_websSSL
#define _h_websSSL 1
/******************************** Description *********************************/
/*
* Header file for the GoAhead Patch for SSL. This defines the interface to
* integrate SSL into the GoAhead Webserver.
*/
/********************************* Includes ***********************************/
#ifdef OPENSSL
#define SSLEAY /* turn off a few special case MONOLITH macros */
#define USE_SOCKETS /* needed for the _O_BINARY defs in the MS world */
#include <openssl/ssl.h>
#else
#include <sslc.h>
#endif
#ifndef UEMF
#include "basic/basic.h"
#include "emf/emf.h"
#else
#include "uemf.h"
#endif
/********************************** Defines ***********************************/
typedef struct {
SSL *ssl;
BIO *bio;
} websSSL_t;
/******************************** Prototypes **********************************/
extern int websSSLOpen();
extern int websSSLIsOpen();
extern void websSSLClose();
extern int websSSLWrite(websSSL_t *wsp, char_t *buf, int nChars);
extern int websSSLGets(websSSL_t *wsp, char_t **buf);
extern int websSSLRead(websSSL_t *wsp, char_t *buf, int nChars);
extern int websSSLEof(websSSL_t *wsp);
extern int websSSLFree(websSSL_t *wsp);
extern int websSSLFlush(websSSL_t *wsp);
extern int websSSLSetKeyFile(char_t *keyFile);
extern int websSSLSetCertFile(char_t *certFile);
#endif /* _h_websSSL */
/*****************************************************************************/

View File

@@ -1,244 +0,0 @@
/*
* websda.c -- Digest Access Authentication routines
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* Routines for generating DAA data. The module uses the
* "RSA Data Security, Inc. MD5 Message-Digest Algorithm" found in md5c.c
*/
/********************************* Includes ***********************************/
#ifndef CE
#include <time.h>
#endif
#include "websda.h"
#include "md5.h"
/******************************** Local Data **********************************/
#define RANDOMKEY T("onceuponatimeinparadise")
#define NONCE_SIZE 34
#define HASH_SIZE 16
/*********************************** Code *************************************/
/*
* websMD5binary returns the MD5 hash
*/
char *websMD5binary(unsigned char *buf, int length)
{
const char *hex = "0123456789abcdef";
MD5_CONTEXT md5ctx;
unsigned char hash[HASH_SIZE];
char *r, *strReturn;
char result[(HASH_SIZE * 2) + 1];
int i;
/*
* Take the MD5 hash of the string argument.
*/
MD5Init(&md5ctx);
MD5Update(&md5ctx, buf, (unsigned int)length);
MD5Final(hash, &md5ctx);
/*
* Prepare the resulting hash string
*/
for (i = 0, r = result; i < 16; i++) {
*r++ = hex[hash[i] >> 4];
*r++ = hex[hash[i] & 0xF];
}
/*
* Zero terminate the hash string
*/
*r = '\0';
/*
* Allocate a new copy of the hash string
*/
strReturn = balloc(B_L, sizeof(result));
strcpy(strReturn, result);
return strReturn;
}
/*****************************************************************************/
/*
* Convenience call to websMD5binary
* (Performs char_t to char conversion and back)
*/
char_t *websMD5(char_t *string)
{
char_t *strReturn;
a_assert(string && *string);
if (string && *string) {
char *strTemp, *strHash;
int nLen;
/*
* Convert input char_t string to char string
*/
nLen = gstrlen(string);
strTemp = ballocUniToAsc(string, nLen + 1);
/*
* Execute the digest calculation
*/
strHash = websMD5binary((unsigned char *)strTemp, nLen);
/*
* Convert the returned char string digest to a char_t string
*/
nLen = strlen(strHash);
strReturn = ballocAscToUni(strHash, nLen);
/*
* Free up the temporary allocated resources
*/
bfree(B_L, strTemp);
bfree(B_L, strHash);
} else {
strReturn = NULL;
}
return strReturn;
}
/******************************************************************************/
/*
* Get a Nonce value for passing along to the client. This function
* composes the string "RANDOMKEY:timestamp:myrealm" and
* calculates the MD5 digest placing it in output.
*/
char_t *websCalcNonce(webs_t wp)
{
char_t *nonce, *prenonce;
struct tm *newtime;
time_t longTime;
a_assert(wp);
/*
* Get time as long integer.
*/
time(&longTime);
/*
* Convert to local time.
*/
newtime = localtime(&longTime);
/*
* Create prenonce string.
*/
prenonce = NULL;
#ifdef DIGEST_ACCESS_SUPPORT
fmtAlloc(&prenonce, 256, T("%s:%s:%s"), RANDOMKEY, gasctime(newtime),
wp->realm);
#else
fmtAlloc(&prenonce, 256, T("%s:%s:%s"), RANDOMKEY, gasctime(newtime),
RANDOMKEY);
#endif
a_assert(prenonce);
/*
* Create the nonce
*/
nonce = websMD5(prenonce);
/*
* Cleanup
*/
bfreeSafe(B_L, prenonce);
return nonce;
}
/******************************************************************************/
/*
* Get an Opaque value for passing along to the client
*/
char_t *websCalcOpaque(webs_t wp)
{
char_t *opaque;
a_assert(wp);
/*
* Temporary stub!
*/
opaque = bstrdup(B_L, T("5ccc069c403ebaf9f0171e9517f40e41"));
return opaque;
}
/******************************************************************************/
/*
* Get a Digest value using the MD5 algorithm
*/
char_t *websCalcDigest(webs_t wp)
{
#ifdef DIGEST_ACCESS_SUPPORT
char_t *digest, *a1, *a1prime, *a2, *a2prime, *preDigest, *method;
a_assert(wp);
digest = NULL;
/*
* Calculate first portion of digest H(A1)
*/
a1 = NULL;
fmtAlloc(&a1, 255, T("%s:%s:%s"), wp->userName, wp->realm, wp->password);
a_assert(a1);
a1prime = websMD5(a1);
bfreeSafe(B_L, a1);
/*
* Calculate second portion of digest H(A2)
*/
method = websGetVar(wp, T("REQUEST_METHOD"), NULL);
a_assert(method);
a2 = NULL;
fmtAlloc(&a2, 255, T("%s:%s"), method, wp->uri);
a_assert(a2);
a2prime = websMD5(a2);
bfreeSafe(B_L, a2);
/*
* Construct final digest KD(H(A1):nonce:H(A2))
*/
a_assert(a1prime);
a_assert(a2prime);
a_assert(wp->nonce);
preDigest = NULL;
if (!wp->qop) {
fmtAlloc(&preDigest, 255, T("%s:%s:%s"), a1prime, wp->nonce, a2prime);
} else {
fmtAlloc(&preDigest, 255, T("%s:%s:%s:%s:%s:%s"),
a1prime,
wp->nonce,
wp->nc,
wp->cnonce,
wp->qop,
a2prime);
}
a_assert(preDigest);
digest = websMD5(preDigest);
/*
* Now clean up
*/
bfreeSafe(B_L, a1prime);
bfreeSafe(B_L, a2prime);
bfreeSafe(B_L, preDigest);
return digest;
#else
return NULL;
#endif /* DIGEST_ACCESS_SUPPORT */
}
/******************************************************************************/

View File

@@ -1,41 +0,0 @@
/*
* websda.h -- GoAhead Digest Access Authentication public header
*
* Copyright (c) GoAhead Software Inc., 1992-2000. All Rights Reserved.
*
* See the file "license.txt" for information on usage and redistribution
*
* $Id$
*/
#ifndef _h_WEBSDA
#define _h_WEBSDA 1
/******************************** Description *********************************/
/*
* GoAhead Digest Access Authentication header. This defines the Digest
* access authentication public APIs. Include this header for files that
* use DAA functions
*/
/********************************* Includes ***********************************/
#ifndef UEMF
#include "basic/basic.h"
#include "emf/emf.h"
#else
#include "uemf.h"
#endif
#include "webs.h"
/****************************** Definitions ***********************************/
extern char_t *websCalcNonce(webs_t wp);
extern char_t *websCalcOpaque(webs_t wp);
extern char_t *websCalcDigest(webs_t wp);
#endif /* _h_WEBSDA */
/******************************************************************************/

View File

@@ -1,217 +0,0 @@
/*
* websuemf.c -- GoAhead Micro Embedded Management Framework
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/********************************** Description *******************************/
/*
* This modules provides compatibility with the full GoAhead EMF.
*/
/*********************************** Includes *********************************/
#include "ejIntrn.h"
#include "wsIntrn.h"
/*********************************** Defines **********************************/
/*
* This structure stores scheduled events.
*/
typedef struct {
void (*routine)(void *arg, int id);
void *arg;
time_t at;
int schedid;
} sched_t;
/*********************************** Locals ***********************************/
static sched_t **sched;
static int schedMax;
/************************************* Code ***********************************/
/*
* Evaluate a script
*/
int scriptEval(int engine, char_t *cmd, char_t **result, int chan)
{
int ejid;
if (engine == EMF_SCRIPT_EJSCRIPT) {
ejid = (int) chan;
/*
* NOTE -- to disable better reporting of ASP errors, change the
* following line of code to
* if (ejEval(ejid, cmd, NULL) ) {
*/
if (ejEval(ejid, cmd, result) ) {
return 0;
} else {
return -1;
}
}
return -1;
}
/******************************************************************************/
/*
* Compare strings, ignoring case: normal strcmp return codes.
*
* WARNING: It is not good form to increment or decrement pointers inside a
* "call" to tolower et al. These can be MACROS, and have undesired side
* effects.
*/
int strcmpci(char_t *s1, char_t *s2)
{
int rc;
a_assert(s1 && s2);
if (s1 == NULL || s2 == NULL) {
return 0;
}
if (s1 == s2) {
return 0;
}
do {
rc = gtolower(*s1) - gtolower(*s2);
if (*s1 == '\0') {
break;
}
s1++;
s2++;
} while (rc == 0);
return rc;
}
/******************************************************************************/
/*
* This function is called when a scheduled process time has come.
*/
void TimerProc(int schedid)
{
sched_t *s;
a_assert(0 <= schedid && schedid < schedMax);
s = sched[schedid];
a_assert(s);
(s->routine)(s->arg, s->schedid);
}
/******************************************************************************/
/*
* Schedule an event in delay milliseconds time. We will use 1 second
* granularity for webServer.
*/
int emfSchedCallback(int delay, emfSchedProc *proc, void *arg)
{
sched_t *s;
int schedid;
if ((schedid = hAllocEntry((void*) &sched, &schedMax,
sizeof(sched_t))) < 0) {
return -1;
}
s = sched[schedid];
s->routine = proc;
s->arg = arg;
s->schedid = schedid;
/*
* Round the delay up to seconds.
*/
s->at = ((delay + 500) / 1000) + time(0);
return schedid;
}
/******************************************************************************/
/*
* Reschedule to a new delay.
*/
void emfReschedCallback(int schedid, int delay)
{
sched_t *s;
if (sched == NULL || schedid == -1 || schedid >= schedMax ||
(s = sched[schedid]) == NULL) {
return;
}
s->at = ((delay + 500) / 1000) + time(0);
}
/******************************************************************************/
void emfUnschedCallback(int schedid)
{
sched_t *s;
if (sched == NULL || schedid == -1 || schedid >= schedMax ||
(s = sched[schedid]) == NULL) {
return;
}
bfree(B_L, s);
schedMax = hFree((void*) &sched, schedid);
}
/******************************************************************************/
/*
* Take the tasks off the queue in a round robin fashion.
*/
void emfSchedProcess()
{
sched_t *s;
int schedid;
static int next = 0;
/*
* If schedMax is 0, there are no tasks scheduled, so just return.
*/
if (schedMax <= 0) {
return;
}
/*
* If next >= schedMax, the schedule queue was reduced in our absence
* so reset next to 0 to start from the begining of the queue again.
*/
if (next >= schedMax) {
next = 0;
}
schedid = next;
for (;;) {
if ((s = sched[schedid]) != NULL && (int)s->at <= (int)time(0)) {
TimerProc(schedid);
next = schedid + 1;
return;
}
if (++schedid >= schedMax) {
schedid = 0;
}
if (schedid == next) {
/*
* We've gone all the way through the queue without finding
* anything to do so just return.
*/
return;
}
}
}
/******************************************************************************/

View File

@@ -1,309 +0,0 @@
/*
* wsIntrn.h -- Internal GoAhead Web server header
*
* Copyright (c) GoAhead Software Inc., 1992-2000. All Rights Reserved.
*
* See the file "license.txt" for information on usage and redistribution
*
* $Id$
*/
#ifndef _h_WEBS_INTERNAL
#define _h_WEBS_INTERNAL 1
/******************************** Description *********************************/
/*
* Internal GoAhead Web Server header. This defines the Web private APIs
* Include this header when you want to create URL handlers.
*/
/*********************************** Defines **********************************/
/*
* Define this to enable logging of web accesses to a file
* #define WEBS_LOG_SUPPORT 1
*
* Define this to enable HTTP/1.1 keep alive support
* #define WEBS_KEEP_ALIVE_SUPPORT 1
*
* Define this to enable if-modified-since support
* #define WEBS_IF_MODIFIED_SUPPORT 1
*
* Define this to support proxy capability and track local vs remote request
* Note: this is not yet fully implemented.
* #define WEBS_PROXY_SUPPORT 1
*
* Define this to support reading pages from ROM
* #define WEBS_PAGE_ROM 1
*
* Define this to enable memory allocation and stack usage tracking
* #define B_STATS 1
*/
/********************************** Includes **********************************/
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#ifdef NETWARE
#include <fcntl.h>
#include <sys/stat.h>
#include <signal.h>
#include <io.h>
#endif
#ifdef WIN
#include <fcntl.h>
#include <sys/stat.h>
#include <io.h>
#endif
#ifdef CE
#ifndef UEMF
#include <io.h>
#endif
#endif
#ifdef NW
#include <fcntl.h>
#include <sys/stat.h>
#endif
#ifdef SCOV5
#include <fcntl.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#endif
#ifdef LYNX
#include <fcntl.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#endif
#ifdef UNIX
#include <fcntl.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#endif
#ifdef QNX4
#include <fcntl.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#include <unix.h>
#endif
#ifdef UW
#include <fcntl.h>
#include <sys/stat.h>
#endif
#ifdef VXWORKS
#include <vxWorks.h>
#include <fcntl.h>
#include <sys/stat.h>
#endif
#ifdef SOLARIS
#include <macros.h>
#include <fcntl.h>
#include <sys/stat.h>
#endif
#ifdef UEMF
#include "uemf.h"
#include "ejIntrn.h"
#else
#include "emf/emfInternal.h"
#include "ej/ejIntrn.h"
#endif
#include "webs.h"
/********************************** Defines ***********************************/
/*
* Read handler flags and state
*/
#define WEBS_BEGIN 0x1 /* Beginning state */
#define WEBS_HEADER 0x2 /* Ready to read first line */
#define WEBS_POST 0x4 /* POST without content */
#define WEBS_POST_CLEN 0x8 /* Ready to read content for POST */
#define WEBS_PROCESSING 0x10 /* Processing request */
#define WEBS_KEEP_TIMEOUT 15000 /* Keep-alive timeout (15 secs) */
#define WEBS_TIMEOUT 60000 /* General request timeout (60) */
#define PAGE_READ_BUFSIZE 512 /* bytes read from page files */
#define MAX_PORT_LEN 10 /* max digits in port number */
#define WEBS_SYM_INIT 64 /* initial # of sym table entries */
/*
* URL handler structure. Stores the leading URL path and the handler
* function to call when the URL path is seen.
*/
typedef struct {
int (*handler)(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg,
char_t *url, char_t *path,
char_t *query); /* Callback URL handler function */
char_t *webDir; /* Web directory if required */
char_t *urlPrefix; /* URL leading prefix */
int len; /* Length of urlPrefix for speed */
int arg; /* Argument to provide to handler */
int flags; /* Flags */
} websUrlHandlerType;
/*
* Webs statistics
*/
typedef struct {
long errors; /* General errors */
long redirects;
long net_requests;
long activeNetRequests;
long activeBrowserRequests;
long timeouts;
long access; /* Access violations */
long localHits;
long remoteHits;
long formHits;
long cgiHits;
long handlerHits;
} websStatsType;
extern websStatsType websStats; /* Web access stats */
/*
* Error code list
*/
typedef struct {
int code; /* HTTP error code */
char_t *msg; /* HTTP error message */
} websErrorType;
/*
* Mime type list
*/
typedef struct {
char_t *type; /* Mime type */
char_t *ext; /* File extension */
} websMimeType;
/*
* File information structure.
*/
typedef struct {
unsigned long size; /* File length */
int isDir; /* Set if directory */
time_t mtime; /* Modified time */
} websStatType;
/*
* Compiled Rom Page Index
*/
typedef struct {
char_t *path; /* Web page URL path */
unsigned char *page; /* Web page data */
int size; /* Size of web page in bytes */
int pos; /* Current read position */
} websRomPageIndexType;
/*
* Defines for file open.
*/
#ifndef CE
#define SOCKET_RDONLY O_RDONLY
#define SOCKET_BINARY O_BINARY
#else /* CE */
#define SOCKET_RDONLY 0x1
#define SOCKET_BINARY 0x2
#endif /* CE */
extern websRomPageIndexType websRomPageIndex[];
extern websMimeType websMimeList[]; /* List of mime types */
extern sym_fd_t websMime; /* Set of mime types */
extern webs_t* webs; /* Session list head */
extern int websMax; /* List size */
extern char_t websHost[64]; /* Name of this host */
extern char_t websIpaddr[64]; /* IP address of this host */
extern char_t *websHostUrl; /* URL for this host */
extern char_t *websIpaddrUrl; /* URL for this host */
extern int websPort; /* Port number */
/******************************** Prototypes **********************************/
extern int websAspOpen();
extern void websAspClose();
extern void websFormOpen();
extern void websFormClose();
extern int websAspWrite(int ejid, webs_t wp, int argc, char_t **argv);
extern void websDefaultClose();
extern int websDefaultHandler(webs_t wp, char_t *urlPrefix,
char_t *webDir, int arg, char_t *url, char_t *path,
char_t *query);
extern int websFormHandler(webs_t wp, char_t *urlPrefix, char_t *webDir,
int arg, char_t *url, char_t *path, char_t *query);
extern int websCgiHandler(webs_t wp, char_t *urlPrefix, char_t *webDir,
int arg, char_t *url, char_t *path, char_t *query);
extern void websCgiCleanup();
extern int websCheckCgiProc(int handle);
extern char_t *websGetCgiCommName();
extern int websLaunchCgiProc(char_t *cgiPath, char_t **argp,
char_t **envp, char_t *stdIn, char_t *stdOut);
extern int websOpen(int sid);
extern void websResponse(webs_t wp, int code, char_t *msg,
char_t *redirect);
extern int websJavaScriptEval(webs_t wp, char_t *script);
extern int websPageReadData(webs_t wp, char *buf, int nBytes);
extern int websPageOpen(webs_t wp, char_t *lpath, char_t *path, int mode,
int perm);
extern void websPageClose(webs_t wp);
extern void websPageSeek(webs_t wp, long offset);
extern int websPageStat(webs_t wp, char_t *lpath, char_t *path,
websStatType *sbuf);
extern int websPageIsDirectory(char_t *lpath);
extern int websRomOpen();
extern void websRomClose();
extern int websRomPageOpen(webs_t wp, char_t *path, int mode, int perm);
extern void websRomPageClose(int fd);
extern int websRomPageReadData(webs_t wp, char *buf, int len);
extern int websRomPageStat(char_t *path, websStatType *sbuf);
extern long websRomPageSeek(webs_t wp, long offset, int origin);
extern void websSetRequestSocketHandler(webs_t wp, int mask,
void (*fn)(webs_t wp));
extern int websSolutionHandler(webs_t wp, char_t *urlPrefix,
char_t *webDir, int arg, char_t *url, char_t *path,
char_t *query);
extern void websUrlHandlerClose();
extern int websUrlHandlerOpen();
extern int websOpenServer(int port, int retries);
extern void websCloseServer();
extern char_t* websGetDateString(websStatType* sbuf);
extern int strcmpci(char_t* s1, char_t* s2);
/*
* Prototypes for functions available when running as part of the
* GoAhead Embedded Management Framework (EMF)
*/
#ifdef EMF
extern int websEmfOpen();
extern void websEmfClose();
extern void websSetEmfEnvironment(webs_t wp);
#endif
#ifdef CE
extern int writeUniToAsc(int fid, void *buf, unsigned int len);
extern int readAscToUni(int fid, void **buf, unsigned int len);
#endif
#endif /* _h_WEBS_INTERNAL */
/******************************************************************************/