Patch from Emmanuel Raguet <raguet@crf.canon.fr> and Eric Valette

<valette@crf.canon.fr> to add a port of the GoAhead web server
(httpd) to the RTEMS build tree.  They have successfully used
this BSP on i386/pc386 and PowerPC/mcp750.

Mark and Joel spoke with Nick Berliner <nickb@goahead.com> on
26 Oct 1999 about this port and got verbal approval to include
it in RTEMS distributions.
This commit is contained in:
Joel Sherrill
1999-10-27 12:50:33 +00:00
parent 79991746da
commit c1cdaa0ce8
68 changed files with 24260 additions and 4 deletions

View File

@@ -5,7 +5,8 @@
AUTOMAKE_OPTIONS = foreign 1.4
ACLOCAL_AMFLAGS = -I $(RTEMS_TOPdir)/aclocal
SUBDIRS = include kern lib libc net netinet nfs rtems rtems_servers wrapup
SUBDIRS = include kern lib libc net netinet nfs rtems rtems_servers \
rtems_webserver wrapup
EXTRA_DIST = \
CHANGELOG \

View File

@@ -5,7 +5,8 @@
AUTOMAKE_OPTIONS = foreign 1.4
ACLOCAL_AMFLAGS = -I $(RTEMS_TOPdir)/aclocal
SUBDIRS = include kern lib libc net netinet nfs rtems rtems_servers wrapup
SUBDIRS = include kern lib libc net netinet nfs rtems rtems_servers \
rtems_webserver wrapup
EXTRA_DIST = \
CHANGELOG \

View File

@@ -42,5 +42,6 @@ netinet/Makefile
nfs/Makefile
rtems/Makefile
rtems_servers/Makefile
rtems_webserver/Makefile
wrapup/Makefile
)

View File

@@ -56,6 +56,9 @@ SRCS = $(H_FILES) $(SYS_H_FILES) $(RTEMS_H_FILES) $(MACHINE_H_FILES) \
$(VM_H_FILES) $(NET_H_FILES) $(NETINET_H_FILES) $(ARPA_H_FILES) \
$(NFS_H_FILES) $(RTEMS_SERVERS_H_FILES)
RTEMS_WEBSERVER_H_PIECES= rtems_webserver
RTEMS_WEBSERVER_H_FILES=$(RTEMS_WEBSERVER_H_PIECES:%=$(srcdir)/../rtems_webserver/%.h)
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(RTEMS_ROOT)/make/leaf.cfg
@@ -87,6 +90,7 @@ preinstall: $(INSTALLDIRS) $(SRCS)
@$(INSTALL_CHANGE) -m 644 $(ARPA_H_FILES) $(PROJECT_INCLUDE)/arpa
@$(INSTALL_CHANGE) -m 644 $(NFS_H_FILES) $(PROJECT_INCLUDE)/nfs
@$(INSTALL_CHANGE) -m 644 $(RTEMS_SERVERS_H_FILES) $(PROJECT_INCLUDE)
@$(INSTALL_CHANGE) -m 644 $(RTEMS_WEBSERVER_H_FILES) $(PROJECT_INCLUDE)
all: preinstall

View File

@@ -0,0 +1,59 @@
#
# $Id$
#
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = ..
subdir = rtems_servers
RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@
LIBNAME = lib.a
LIB = ${ARCH}/${LIBNAME}
# C and C++ source names, if any, go here -- minus the .c or .cc
C_PIECES=asp balloc wbase64 default ejlex ejparse form h handler mime \
misc webpage ringq rom security socket sym uemf url value webcomp \
webrom webs websuemf webmain
C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
SRCS = $(C_FILES)
OBJS = $(C_O_FILES)
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(RTEMS_ROOT)/make/lib.cfg
INSTALL_CHANGE = @INSTALL_CHANGE@
#
# Add local stuff here using +=
#
DEFINES += -DWEBS -DUEMF -DOS="LINUX" -DLINUX
CPPFLAGS +=
CFLAGS +=
#
# Add your list of files to delete here. The config files
# already know how to delete some stuff, so you may want
# to just run 'make clean' first to see what gets missed.
# 'make clobber' already includes 'make clean'
#
CLEAN_ADDITIONS += $(LIB)
CLOBBER_ADDITIONS +=
all: ${ARCH} $(LIB)
$(LIB): $(SRCS) ${OBJS}
$(make-library)
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status

View File

@@ -0,0 +1,313 @@
/*
* asp.c -- Active Server Page Support
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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 */
/***************************** 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()
{
/*
* Create the table for ASP functions
*/
websAspFunctions = symOpen(128);
/*
* Create standard ASP commands
*/
websAspDefine(T("write"), websAspWrite);
return 0;
}
/************************************* Code ***********************************/
/*
* Close Asp symbol table.
*/
void websAspClose()
{
if (websAspFunctions != -1) {
symClose(websAspFunctions, NULL);
}
}
/******************************************************************************/
/*
* 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 incase 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;
}
websCloseFileHandle(wp);
/*
* Convert to UNICODE if necessary.
*/
if ((buf = ballocAscToUni(rbuf)) == 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)) {
websCloseFileHandle(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));
a_assert(argv);
for (i = 0; i < argc; ) {
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

@@ -0,0 +1,836 @@
/*
* balloc.c -- Block allocation module
*
* Copyright (c) GoAhead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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 modules 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
#if UEMF
#include "uemf.h"
#else
#include "basic/basicInternal.h"
#endif
#include <stdarg.h>
#include <stdlib.h>
#if !NO_BALLOC
/********************************* Defines ************************************/
typedef struct {
union {
void *next; /* Pointer to next in q */
int size; /* Actual requested size */
} u;
int flags; /* Per block allocation flags */
} bType;
/*
* Define B_STATS if you wish to track memory block and stack usage
*/
#if 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 allocs; /* Count of alloc attempts */
} 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; /* Max block entry */
static int bStatsFilesMax; /* Max file entry */
static int bStatsMemInUse; /* Memory currently in use */
static int bStatsMemMax; /* Max memory ever used */
static void *bStackMin = (void*) -1;/* Miniumum stack position */
static void *bStackStart; /* Starting stack position */
static int bStatsMemMalloc; /* Malloced memory */
#endif /* B_STATS */
/********************************** 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 */
/*************************** Forward Declarations *****************************/
#if 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 B_FILL || B_VERIFY_CAUSES_SEVERE_OVERHEAD
static void bFillBlock(void *buf, int bufsize);
#endif
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
static void verifyUsedBlock(bType *bp, int q);
static void verifyFreeBlock(bType *bp, int q);
static void verifyBallocSpace();
#endif
/********************************** 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;
if (buf == NULL) {
if (bufsize == 0) {
bufsize = B_DEFAULT_MEM;
}
if ((buf = malloc(bufsize)) == NULL) {
return -1;
}
#if B_STATS
bStatsMemMalloc += bufsize;
#endif
} else {
bFlags |= B_USER_BUF;
}
bFreeSize = bFreeLeft = bufsize;
bFreeBuf = bFreeNext = buf;
#if B_FILL || B_VERIFY_CAUSES_SEVERE_OVERHEAD
bFillBlock(buf, bufsize);
#endif
#if B_STATS
bStackStart = &buf;
#endif
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyFreeBlock(buf, bufsize);
#endif
return 0;
}
/******************************************************************************/
/*
* Close down the balloc module and free all malloced memory.
*/
void bclose()
{
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyBallocSpace();
#endif
if (! (bFlags & B_USER_BUF)) {
free(bFreeBuf);
}
}
/******************************************************************************/
/*
* 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, mask;
/*
* 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;
}
}
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyBallocSpace();
#endif
if (size < 0) {
return NULL;
}
/*
* Determine the relevant block queue with a block big enough --
* include room for the block header.
*/
mask = (size + sizeof(bType)) >> B_SHIFT;
for (q = 0; mask; mask >>= 1) {
q++;
}
a_assert(0 <= q && q <= B_MAX_CLASS);
memSize = (1 << (B_SHIFT + q));
if (q >= B_MAX_CLASS) {
/*
* Size if bigger than the maximum class. Malloc if use has been okayed
*/
if (bFlags & B_USE_MALLOC) {
#if B_STATS
bstats(0, NULL);
#endif
bp = (bType*) malloc(memSize);
if (bp == NULL) {
trace(0, T("B: malloc failed for %s:%d, size %d\n"),
B_ARGS, memSize);
return NULL;
}
#if B_STATS
bStatsMemMalloc += memSize;
#endif
#if B_FILL || B_VERIFY_CAUSES_SEVERE_OVERHEAD
bFillBlock(bp, memSize);
#endif
} else {
trace(0, T("B: balloc failed for %s:%d, size %d\n"),
B_ARGS, memSize);
return NULL;
}
bp->u.size = size;
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;
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyFreeBlock(bp, q);
#endif
#if B_FILL || B_VERIFY_CAUSES_SEVERE_OVERHEAD
bFillBlock(bp, memSize);
#endif
bp->u.size = size;
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;
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyFreeBlock(bp, q);
#endif
bFreeNext += memSize;
bFreeLeft -= memSize;
#if B_FILL || B_VERIFY_CAUSES_SEVERE_OVERHEAD
bFillBlock(bp, memSize);
#endif
bp->u.size = size;
bp->flags = 0;
} else if (bFlags & B_USE_MALLOC) {
static int once = 0;
if (once++ < 20) {
#if B_STATS
bstats(0, NULL);
#endif
}
/*
* Nothing left on the primary free list, so malloc a new block
*/
if ((bp = (bType*) malloc(memSize)) == NULL) {
trace(0, T("B: malloc failed for %s:%d size %d\n"),
B_ARGS, memSize);
return NULL;
}
#if B_STATS
bStatsMemMalloc += memSize;
#endif
#if B_FILL || B_VERIFY_CAUSES_SEVERE_OVERHEAD
bFillBlock(bp, memSize);
#endif
bp->u.size = size;
bp->flags = B_MALLOCED;
} else {
trace(0, T("B: alloc failed for %s:%d size %d\n"), B_ARGS, size);
return NULL;
}
}
#if B_STATS
bStatsAlloc(B_ARGS, bp, q, size);
#endif
bp->flags |= B_INTEGRITY;
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 mask, q;
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyBallocSpace();
#endif
a_assert(mp);
bp = (bType*) ((char*) mp - sizeof(bType));
a_assert((bp->flags & B_INTEGRITY_MASK) == B_INTEGRITY);
if ((bp->flags & B_INTEGRITY_MASK) != B_INTEGRITY) {
return;
}
/*
* Determine the relevant block queue
*/
mask = (bp->u.size + sizeof(bType)) >> B_SHIFT;
for (q = 0; mask; mask >>= 1) {
q++;
}
a_assert(0 <= q && q <= B_MAX_CLASS);
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyUsedBlock(bp,q);
#endif
if (bp->flags & B_MALLOCED) {
free(bp);
return;
}
#if B_STATS
bStatsFree(B_ARGS, bp, q, bp->u.size);
#endif
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
bFillBlock(bp, 1 << (B_SHIFT + q));
#endif
/*
* Simply link onto the head of the relevant q
*/
bp->u.next = bQhead[q];
bQhead[q] = bp;
}
/******************************************************************************/
/*
* Safe free
*/
void bfreeSafe(B_ARGS_DEC, void *mp)
{
if (mp) {
bfree(B_ARGS, mp);
}
}
/******************************************************************************/
#if 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 ((newbuf = balloc(B_ARGS, newsize)) != NULL) {
memcpy(newbuf, mp, bp->u.size);
bfree(B_ARGS, mp);
}
return newbuf;
}
/******************************************************************************/
#if B_FILL || 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
/******************************************************************************/
#if 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;
bType *bp;
int q, count, mem, total;
static int recurseProtect = 0;
if (recurseProtect++ > 0) {
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) {
a_assert((bp->flags & B_INTEGRITY_MASK) == B_INTEGRITY);
count++;
}
mem = count * (1 << (q + B_SHIFT));
total += mem;
(*writefn)(handle,
T("%2d %5d %3d %5d %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
*/
(*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("Memory currently in use %7d\n"), bStatsMemInUse);
(*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
*/
qsort(bStatsFiles, bStatsFilesMax, sizeof(bStatsFileType), bStatsFileSort);
(*writefn)(handle, T("\nPer File Memory Stats\n"));
total = 0;
for (fp = bStatsFiles; fp < &bStatsFiles[bStatsFilesMax]; fp++) {
if (fp->file[0]) {
(*writefn)(handle,
T("%18s, bytes %7d, blocks in use %5d, total allocs %6d\n"),
fp->file, fp->allocated, fp->count, fp->allocs);
total += fp->allocated;
}
}
(*writefn)(handle, T("\nTotal allocated %7d\n"), total);
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;
}
/******************************************************************************/
/*
* Default output function. Just send to trace channel.
*/
static void bstatsWrite(int handle, char_t *fmt, ...)
{
va_list args;
char_t *buf;
va_start(args, fmt);
buf = NULL;
gvsnprintf(&buf, VALUE_MAX_STRING, fmt, args);
va_end(args);
trace(0, buf);
if (buf) {
bfree(B_L, buf);
}
}
/******************************************************************************/
/*
* Accumulate allocation statistics
*/
static void bStatsAlloc(B_ARGS_DEC, void *ptr, int q, int size)
{
bStatsFileType *fp;
bStatsBlkType *bp;
char_t name[FNAMESIZE + 10];
a_assert(file && *file);
a_assert(0 <= q && q <= B_MAX_CLASS);
a_assert(size > 0);
gsprintf(name, T("%s:%d"), B_ARGS);
bStats[q].alloc++;
bStats[q].inuse++;
bStatsMemInUse += size;
if (bStatsMemInUse > bStatsMemMax) {
bStatsMemMax = bStatsMemInUse;
}
/*
* 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->allocs++;
break;
}
}
/*
* Find the first free slot for this file and add current block size.
*/
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->allocs++;
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)
{
bStatsFileType *fp;
bStatsBlkType *bp;
char_t name[FNAMESIZE + 10];
a_assert(file && *file);
a_assert(0 <= q && q <= B_MAX_CLASS);
a_assert(size > 0);
bStatsMemInUse -= size;
bStats[q].inuse--;
gsprintf(name, T("%s:%d"), B_ARGS);
/*
* Update the per block stats
*/
for (bp = bStatsBlks; bp < &bStatsBlks[bStatsBlksMax]; bp++) {
if (bp->ptr == ptr) {
bp->ptr = NULL;
fp = bp->who;
fp->allocated -= size;
fp->count--;
return;
}
}
a_assert(0);
}
#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 */
/******************************************************************************/
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
/*
* The following routines verify the integrity of the balloc memory space.
* These functions depend 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));
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));
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.
*/
static void verifyBallocSpace()
{
char *p;
bType *bp;
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()
{
}
/******************************************************************************/
#if UNICODE
char_t* bstrdupNoBalloc(char_t* s)
{
if (s) {
return wcsdup(s);
} else {
return wcsdup(T(""));
}
}
#endif /* UNICODE */
/******************************************************************************/
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

@@ -0,0 +1,389 @@
/*
* default.c -- Default URL handler. Includes support for ASP.
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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;
char_t *date;
int bytes, flags, nchars;
a_assert(websValid(wp));
a_assert(url && *url);
a_assert(path && *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;
tmp = NULL;
gsnprintf(&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("Can't open document <b>%s</b><br>for URL <b>%s</b>"),
lpath, url);
return 1;
}
if (websPageStat(wp, lpath, path, &sbuf) < 0) {
websError(wp, 400, T("Can't stat page <b>%s</b><br>for URL <b>%s</b>"),
lpath, url);
}
/*
* 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++;
#if 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: GoAhead-Webs\r\n"));
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: GoAhead-Webs\r\n"));
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"));
/*
* Evaluate ASP requests
*/
if (flags & WEBS_ASP) {
if (websAspRequest(wp, lpath) < 0) {
return 1;
}
websDone(wp, 200);
return 1;
}
/*
* All done if the browser did a HEAD request
*/
if (flags & WEBS_HEAD_REQUEST) {
websDone(wp, 200);
return 1;
}
/*
* For normal web documents, return the data via background write
*/
websSetRequestSocketHandler(wp, SOCKET_WRITABLE, websDefaultWriteEvent);
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;
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) {
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);
wrote = 0;
bytes = 0;
written = websGetRequestWritten(wp);
/*
* We only do this for non-ASP documents
*/
if ( !(flags & WEBS_ASP)) {
bytes = websGetRequestBytes(wp);
/*
* Note: websWriteBlock 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 = websWriteBlockData(wp, buf, len)) < 0) {
break;
}
written += wrote;
if (wrote != len) {
websPageSeek(wp, - (wrote - len));
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);
}
if (websDefaultDir) {
bfree(B_L, websDefaultDir);
}
}
/******************************************************************************/
/*
* 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

@@ -0,0 +1,226 @@
/*
* ej.h -- Ejscript(TM) header
*
* Copyright (c) Go Ahead Software, Inc., 1992-1999
*
* See the file "license.txt" for information on usage and redistribution
*/
#ifndef _h_EJ
#define _h_EJ 1
/******************************** Description *********************************/
/*
* Go Ahead Ejscript(TM) header. This defines the Ejscript API and internal
* structures.
*/
/********************************* Includes ***********************************/
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#ifndef CE
#include <fcntl.h>
#endif
#if LYNX
#include <unistd.h>
#endif
#ifdef QNX4
#include <dirent.h>
#endif
#if UEMF
#include "uemf.h"
#else
#include <param.h>
#include <stat.h>
#include "basic/basicInternal.h"
#include "emf/emf.h"
#include "webs/webs.h"
#endif
/********************************** Defines ***********************************/
/*
* Constants
*/
#define EJ_INC 110 /* Growth for tags/tokens */
#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 /* -- */
/*
* 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_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 ejOpenEngine(sym_fd_t variables, sym_fd_t functions);
extern void ejCloseEngine(int eid);
extern int ejOpenBlock(int eid);
extern int ejCloseBlock(int eid, int vid);
extern char_t *ejEval(int eid, char_t *script, char_t **emsg);
extern char_t *ejEvalBlock(int eid, char_t *script, char_t **emsg);
extern char_t *ejEvalFile(int eid, char_t *path, char_t **emsg);
extern int ejSetGlobalFunction(int eid, char_t *name,
int (*fn)(int eid, void *handle, int argc, char_t **argv));
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 int ejArgs(int argc, char_t **argv, char_t *fmt, ...);
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 void ejSetResult(int eid, char_t *s);
extern char_t *ejGetResult(int eid);
extern void ejSetVar(int eid, char_t *var, char_t *value);
extern void ejSetLocalVar(int eid, char_t *var, char_t *value);
extern int ejGetVar(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 ejEmfTrace(int eid, void *handle, int argc, char_t **argv);
extern int ejEmfDbWrite(int eid, void *handle, int argc, char_t **argv);
#endif /* _h_EJ */
/*****************************************************************************/

View File

@@ -0,0 +1,679 @@
/*
* ejlex.c -- Ejscript(TM) Lexical Analyser
*
* Copyright (c) Go Ahead Software, Inc., 1995-1999
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** Description *********************************/
/*
* Ejscript lexical analyser. This implementes a lexical analyser for a
* a subset of the JavaScript language.
*/
/********************************** Includes **********************************/
#include "ej.h"
#if UEMF
#include "uemf.h"
#else
#include "basic/basicInternal.h"
#endif
/****************************** 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);
/************************************* 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_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);
}
}
/******************************************************************************/
/*
* Get the next Ejscript token
*/
int ejLexGetToken(ej_t* ep, int state)
{
ep->tid = getLexicalToken(ep, state);
trace(7, 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, back_quoted, lval, i;
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 '!': /* "!=" */
if ((c = inputGetc(ep)) < 0) {
ejError(ep, T("Syntax Error"));
return TOK_ERR;
}
if (c == '=') {
tokenAddChar(ep, EXPR_NOTEQ);
return TOK_EXPR;
}
tokenAddChar(ep, COND_NOT);
return TOK_LOGICAL;
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;
}
back_quoted = 0;
while (c != quote) {
if (c == '\\' && !back_quoted) {
back_quoted++;
} else if (back_quoted) {
if (gisdigit((char_t) c)) {
lval = 0;
for (i = 0; i < 3; i++) {
if ('0' <= c && c <= '7') {
break;
}
lval = lval * 8 + c;
if ((c = inputGetc(ep)) < 0) {
break;
}
}
c = (int) lval;
} else if (back_quoted) {
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':
lval = 0;
for (i = 0; i < 2; i++) {
if (! gisxdigit((char_t) c)) {
break;
}
lval = lval * 16 + c;
if ((c = inputGetc(ep)) < 0) {
break;
}
}
c = (int) lval;
break;
case 'u':
lval = 0;
for (i = 0; i < 4; i++) {
if (! gisxdigit((char_t) c)) {
break;
}
lval = lval * 16 + c;
if ((c = inputGetc(ep)) < 0) {
break;
}
}
c = (int) lval;
break;
case '\'':
case '\"':
break;
}
}
back_quoted = 0;
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((char_t) c));
inputPutback(ep, c);
return TOK_LITERAL;
default:
/*
* Identifiers or a function names
*/
back_quoted = 0;
while (1) {
if (c == '\\' && !back_quoted) {
back_quoted++;
} else {
back_quoted = 0;
if (tokenAddChar(ep, c) < 0) {
break;
}
}
if ((c = inputGetc(ep)) < 0) {
break;
}
if (!back_quoted && (!gisalnum((char_t) 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) {
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';
}
/******************************************************************************/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,163 @@
/*
* form.c -- Form processing (in-memory CGI) for the GoAhead Web server
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/********************************** 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);
if (websValid(wp)) {
websError(wp, 200, T("Form didn't call websDone"));
}
}
}
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))
{
static int once = 0;
a_assert(name && *name);
a_assert(fn);
if (fn == NULL) {
return -1;
}
if (once++ == 0) {
websFormOpen();
}
symEnter(formSymtab, name, valueInteger((int) fn), (int) NULL);
return 0;
}
/******************************************************************************/
/*
* Open the symbol table for forms.
*/
void websFormOpen()
{
formSymtab = symOpen(64);
}
/******************************************************************************/
/*
* Close the symbol table for forms.
*/
void websFormClose()
{
if (formSymtab != -1) {
symClose(formSymtab, NULL);
}
}
/******************************************************************************/
/*
* 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: GoAhead-Webs\r\n"));
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

@@ -0,0 +1,171 @@
/*
* h.c -- Handle allocation module
*
* Copyright (c) GoAhead Software Inc., 1995-1999. All Rights Reserved.
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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 ***********************************/
#if 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.
*/
int hAlloc(void ***map)
{
int *mp;
int handle, len, memsize, incr;
a_assert(map);
if (*map == NULL) {
incr = H_INCR;
memsize = (incr + H_OFFSET) * sizeof(void**);
if ((mp = (int*) balloc(B_L, memsize)) == NULL) {
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.
*/
int hAllocEntry(void ***list, int *max, int size)
{
char_t *cp;
int id;
a_assert(list);
a_assert(max);
if ((id = hAlloc((void***) list)) < 0) {
return -1;
}
if (size > 0) {
if ((cp = balloc(B_L, size)) == NULL) {
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

@@ -0,0 +1,284 @@
/*
* handler.c -- URL handler support
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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 */
/**************************** 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);
/*********************************** Code *************************************/
/*
* Initialize the URL handler module
*/
int websUrlHandlerOpen()
{
websAspOpen();
return 0;
}
/******************************************************************************/
/*
* Close the URL handler module
*/
void websUrlHandlerClose()
{
websUrlHandlerType* sp;
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);
/*
* 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 was
* the handlers responsibility to call websDone
*/
if (i >= websUrlHandlerMax) {
websError(wp, 200, T("No handler for this URL %s"), wp->url);
}
return 0;
}
/******************************************************************************/

View File

@@ -0,0 +1,112 @@
/*
* mime.c -- Web server mime types
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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") },
#if 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

@@ -0,0 +1,581 @@
/*
* misc.c -- Miscellaneous routines.
*
* Copyright (c) GoAhead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/********************************* Includes ***********************************/
#if UEMF
#include "uemf.h"
#else
#include "basic/basicInternal.h"
#endif
/********************************* Defines ************************************/
/*
* Sprintf buffer structure. Make the increment 8 less than 64 so that
* a balloc can use a 64 byte block.
*/
#define STR_REALLOC 0x1 /* Reallocate the buffer as required */
#define STR_INC 58 /* 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);
static int strnlen(char_t *s, unsigned int n);
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 and LynxOS have their own basename function
*/
#if ! LINUX & ! LYNX
char_t *basename(char_t* name)
{
char_t *cp;
#if NW || 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 */
/******************************************************************************/
/*
* 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 WIN || 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
* gsnprintf and gvsnprintf instead! These functions do _not_ support floating
* point, like %e, %f, %g...
*/
int gsnprintf(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 = gvsnprintf(s, n, fmt, ap);
va_end(ap);
return result;
}
/******************************************************************************/
/*
* This function appends the formatted string to the supplied string,
* reallocing if required.
*/
int gsprintfRealloc(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 gvsnprintf(char_t **s, int n, char_t *fmt, va_list arg)
{
a_assert(s);
a_assert(fmt);
return dsnprintf(s, n, fmt, arg, 0);
}
/******************************************************************************/
/*
* Dynamic sprintf implementation. Supports dynamic buffer allocation also.
* 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(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(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 {
put_ulong(&buf, value, 16, 0, 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
*/
static int strnlen(char_t *s, unsigned int n)
{
unsigned int len;
len = gstrlen(s);
return min(len, n);
}
/******************************************************************************/
/*
* Add a character to a string buffer
*/
static void put_char(strbuf_t *buf, char_t c)
{
if (buf->count >= buf->size) {
if (! (buf->flags & STR_REALLOC)) {
return;
}
buf->size += STR_INC;
if (buf->size > buf->max && buf->size > STR_INC) {
a_assert(buf->size <= buf->max);
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;
++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)) {
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)
{
#if UNICODE
if (MultiByteToWideChar(CP_ACP, 0, str, nBytes / sizeof(char_t), ubuf,
nBytes / sizeof(char_t)) < 0) {
return (char_t*) str;
}
#else
memcpy(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)
{
#if UNICODE
if (WideCharToMultiByte(CP_ACP, 0, ustr, nBytes, buf, nBytes, NULL,
NULL) < 0) {
return (char*) ustr;
}
#else
memcpy(buf, ustr, nBytes);
#endif
return (char*) buf;
}
/******************************************************************************/
/*
* allocate (balloc) a buffer and do ascii to unicode conversion into it.
* cp points to the ascii string which must be NULL terminated.
* Return a pointer to the unicode buffer which must be bfree'd later.
* Return NULL on failure to get buffer.
*/
char_t *ballocAscToUni(char * cp)
{
char_t * unip;
int ulen;
ulen = (strlen(cp) + 1) * sizeof(char_t);
if ((unip = balloc(B_L, ulen)) == NULL) {
return NULL;
}
ascToUni(unip, cp, ulen);
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 including teminating null, if there is one.
* Return a pointer to the ascii buffer which must be bfree'd later.
* Return NULL on failure to get buffer.
*/
char *ballocUniToAsc(char_t * unip, int ulen)
{
char * cp;
if ((cp = balloc(B_L, ulen)) == NULL) {
return NULL;
}
uniToAsc(cp, unip, ulen);
return cp;
}
/******************************************************************************/

View File

@@ -0,0 +1,537 @@
/*
* ringq.c -- Ring queue buffering module
*
* Copyright (c) GoAhead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** Description *********************************/
/*
* A ring queue allows maximum utilization of memory for data storage and is
* ideal for input/output buffering. This module provides a highly effecient
* 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 fillers responsibility to ensure
* the ringq is never filled such that servp == endp.
*
* It is the fillers 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 ***********************************/
#if 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 ringq_grow(ringq_t *rq);
/*********************************** 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 increment, int maxsize)
{
a_assert(rq);
a_assert(increment >= 0);
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 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) && !ringq_grow(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) && !ringq_grow(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 wide null (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;
}
/******************************************************************************/
#if 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 && !ringq_grow(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 && !ringq_grow(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 (! ringq_grow(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);
rq->servp = rq->buf;
rq->endp = rq->buf;
*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 ringq_grow(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);
#if 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);
return 1;
}
/******************************************************************************/

View File

@@ -0,0 +1,198 @@
/*
* rom.c -- Support for ROMed page retrieval.
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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>
#if CE
#define EINVAL 22
#define EBADF 9
#else
#include <errno.h>
#endif
#include "wsIntrn.h"
/******************************** Local Data **********************************/
#if 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(64);
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, NULL);
}
/******************************************************************************/
/*
* 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
/******************************************************************************/

View File

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

View File

@@ -0,0 +1,109 @@
/*
* security.c -- Security handler
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** Description *********************************/
/*
* This module provides a basic security policy. It supports a single global
* password and ignores the username. Encoding/decoding of the password is
* -not- done.
*/
/********************************* Includes ***********************************/
#include "wsIntrn.h"
/******************************** Local Data **********************************/
static char_t websPassword[WEBS_MAX_PASS]; /* Access password (decoded) */
/*********************************** 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, *password;
int flags;
a_assert(websValid(wp));
a_assert(url && *url);
a_assert(path && *path);
/*
* Get the critical request details
*/
type = websGetRequestType(wp);
password = websGetRequestPassword(wp);
flags = websGetRequestFlags(wp);
/*
* Validate the users password if required (local access is always allowed)
* We compare the decoded form of the password.
*/
if (*websPassword && !(flags & WEBS_LOCAL_REQUEST)) {
if (password && *password) {
if (gstrcmp(password, websPassword) != 0) {
websStats.access++;
websError(wp, 200, T("Access Denied\nWrong Password"));
websSetPassword(T(""));
return 1;
}
} else {
/*
* This will cause the browser to display a password / username
* dialog
*/
websStats.errors++;
websError(wp, 401, T("<html><head>Access Denied</head><body>\r\n\
Access to this document requires a password.</body>\
</html>\r\n"));
return 1;
}
}
return 0;
}
/******************************************************************************/
/*
* 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 websPassword;
}
/******************************************************************************/

View File

@@ -0,0 +1,991 @@
/*
* socket.c -- Socket support module for UNIX
*
* Copyright (c) Go Ahead, 1995-1999
*/
/******************************** Description *********************************/
/*
* SCO Unix Socket Module. This supports non-blocking buffered socket I/O.
*/
/********************************** Includes **********************************/
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "uemf.h"
/*********************************** Defines **********************************/
typedef struct {
char host[64]; /* Host name */
ringq_t inBuf; /* Input ring queue */
ringq_t outBuf; /* Output ring queue */
ringq_t lineBuf; /* Line ring queue */
socketAccept_t accept; /* Accept handler */
socketHandler_t handler; /* User I/O handler */
int handler_data; /* User handler data */
int sid; /* Index into socket[] */
int port; /* Port to listen on */
int flags; /* Current state flags */
int readyMask; /* Events now ready */
int interestMask; /* Events interest */
int error; /* Last error */
int sock; /* Actual socket handle */
} socket_t;
/************************************ Locals **********************************/
static socket_t** socketList; /* List of open sockets */
static int socketMax; /* Maximum size of socket */
static int socketHighestFd = -1; /* Highest socket fd opened */
/***************************** Forward Declarations ***************************/
static int socketAlloc(char* host, int port, socketAccept_t accept, int flags);
static void socketFree(int sid);
static void socketAccept(socket_t* sp);
static int socketGetInput(int sid, char* buf, int toRead, int* errCode);
static int socketDoOutput(socket_t* sp, char* buf, int toWrite, int* errCode);
static int socketDoEvent(socket_t *sp);
static int socketGetError();
static int socketWaitForEvent(socket_t* sp, int events, int* errCode);
static int socketNonBlock(socket_t *sp);
static socket_t* socketPtr(int sid);
/*********************************** Code *************************************/
/*
* Open socket module
*/
int socketOpen()
{
return 0;
}
/******************************************************************************/
/*
* Close the socket module, by closing all open connections
*/
void socketClose()
{
int i;
for (i = socketMax; i >= 0; i--) {
if (socketList && socketList[i]) {
socketCloseConnection(i);
}
}
}
/******************************************************************************/
/*
* Open a client or server socket. Host is NULL if we want server capability.
*/
int socketOpenConnection(char* host, int port, socketAccept_t accept, int flags)
{
socket_t *sp;
struct sockaddr_in sockaddr;
struct hostent *hostent; /* Host database entry */
int sid, rc;
/*
* Allocate a socket structure
*/
if ((sid = socketAlloc(host, port, accept, flags)) < 0) {
return -1;
}
sp = socketList[sid];
a_assert(sp);
/*
* Create the socket address structure
*/
memset((char *) &sockaddr, '\0', sizeof(struct sockaddr_in));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons((short) (port & 0xFFFF));
if (host == NULL) {
sockaddr.sin_addr.s_addr = INADDR_ANY;
} else {
sockaddr.sin_addr.s_addr = inet_addr(host);
if (sockaddr.sin_addr.s_addr == INADDR_NONE) {
hostent = gethostbyname(host);
if (hostent != NULL) {
memcpy((char *) &sockaddr.sin_addr,
(char *) hostent->h_addr_list[0],
(size_t) hostent->h_length);
} else {
errno = ENXIO;
socketFree(sid);
return -1;
}
}
}
/*
* Create the socket. Set the close on exec flag so children don't
* inherit the socket.
*/
sp->sock = socket(AF_INET, SOCK_STREAM, 0);
if (sp->sock < 0) {
socketFree(sid);
return -1;
}
fcntl(sp->sock, F_SETFD, FD_CLOEXEC);
socketHighestFd = max(socketHighestFd, sp->sock);
/*
* Host is set if we are the client
*/
if (host) {
/*
* Connect to the remote server
*/
if (connect(sp->sock, (struct sockaddr *) &sockaddr,
sizeof(sockaddr)) < 0) {
socketFree(sid);
return -1;
}
socketNonBlock(sp);
} else {
/*
* Bind to the socket endpoint with resule and the call listen()
** to start listening
*/
rc = 1;
setsockopt(sp->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&rc, sizeof(rc));
if (bind(sp->sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr))
< 0) {
socketFree(sid);
return -1;
}
sp->flags |= SOCKET_LISTENING;
if (listen(sp->sock, SOMAXCONN) < 0) {
socketFree(sid);
return -1;
}
sp->interestMask = SOCKET_READABLE;
}
return sid;
}
/******************************************************************************/
/*
* Close a socket
*/
void socketCloseConnection(int sid)
{
socket_t* sp;
if ((sp = socketPtr(sid)) == NULL) {
return;
}
/*
* We always flush all output before closing. Unlink from the emf event
* mechanism and then free (and close) the connection
*/
socketFlush(sid, 1);
socketFree(sid);
}
/******************************************************************************/
/*
* Accept a connection. Called by socketDoEvent
*/
static void socketAccept(socket_t* sp)
{
struct sockaddr_in addr;
socket_t *nsp;
size_t len;
int newSock, nid;
a_assert(sp);
/*
* Accept the connection and prevent inheriting by children (F_SETFD)
*/
len = sizeof(struct sockaddr_in);
if ((newSock = accept(sp->sock, (struct sockaddr *) &addr, &len)) < 0) {
return;
}
fcntl(newSock, F_SETFD, FD_CLOEXEC);
socketHighestFd = max(socketHighestFd, newSock);
/*
* Create a socket structure and insert into the socket list
*/
nid = socketAlloc(sp->host, sp->port, sp->accept, 0);
nsp = socketList[nid];
a_assert(nsp);
nsp->sock = newSock;
if (nsp == NULL) {
return;
}
/*
* Call the user accept callback, the user must call socketCreateHandler
* to register for further events of interest.
*/
if (sp->accept != NULL) {
if ((sp->accept)(nid, inet_ntoa(addr.sin_addr),
ntohs(addr.sin_port)) < 0) {
socketFree(nid);
return;
}
}
socketNonBlock(nsp);
}
/******************************************************************************/
/*
* Write to a socket. This may block if the underlying socket cannot
* absorb the data. 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
* Flush when the ringq is too full and continue.
*/
rq = &sp->outBuf;
for (bytesWritten = 0; bufsize > 0; ) {
if ((room = ringqPutBlkMax(rq)) == 0) {
if (socketFlush(sid, 0) < 0) {
return -1;
}
if ((room = ringqPutBlkMax(rq)) == 0) {
break;
}
continue;
}
len = min(room, bufsize);
ringqPutBlk(rq, (unsigned char*) buf, len);
bytesWritten += len;
bufsize -= len;
buf += len;
}
return bytesWritten;
}
/******************************************************************************/
/*
* 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. Since
* this may be zero, callers should use socketEof() to distinguish between
* this and EOF. Note: this ignores the line buffer, so a previous socketGets
* which read a partial line may cause a subsequent socketRead to miss
* some data.
*/
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) {
room = ringqPutBlkMax(rq);
len = socketGetInput(sid, (char*) rq->endp, room, &errCode);
if (len < 0) {
if (errCode == EWOULDBLOCK) {
if (bytesRead >= 0) {
return bytesRead;
}
}
return -1;
} else if (len == 0) {
/*
* This is EOF, but we may have already read some data so pass that
* back first before notifying EOF. The next read will return 0
* to indicate 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. It returns -1 for error, EOF or when no complete line yet read.
* Otherwise the length of the line is returned. 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** buf)
{
socket_t* sp;
ringq_t* lq;
char c;
int rc, len;
a_assert(buf);
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
lq = &sp->lineBuf;
while (1) {
if ((rc = socketRead(sid, &c, 1)) < 0) {
return rc;
} else 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) {
if ((*buf = balloc(B_L, len + 1)) == NULL) {
return -1;
}
memset(*buf, 0, len + 1);
ringqGetBlk(lq, (unsigned char*) *buf, len);
} else {
*buf = NULL;
}
return len;
} else if (c == '\r') {
continue;
}
ringqPutc(lq, c);
}
}
/******************************************************************************/
/*
* Flush a socket. Do not wait, just initiate output and return.
* This will return -1 on errors and 0 if successful.
*/
int socketFlush(int sid, int block)
{
socket_t* sp;
ringq_t* rq;
int len, bytesWritten, errCode;
a_assert(block == 0 || block == 1);
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
rq = &sp->outBuf;
/*
* Set the background flushing flag which socketDoEvent will check to
* continue the flush.
*/
if (!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 (! block) {
return 0;
}
if (socketWaitForEvent(sp, SOCKET_WRITABLE | SOCKET_EXCEPTION,
&errCode)) {
continue;
}
}
return -1;
}
ringqGetBlkAdj(rq, bytesWritten);
if (! block) {
break;
}
}
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;
}
/******************************************************************************/
/*
* Create a user handler for this socket. The handler called whenever there
* is an event of interest as defined by interestMask (SOCKET_READABLE, ...)
*/
void socketCreateHandler(int sid, int interestMask, socketHandler_t handler,
int data)
{
socket_t* sp;
if ((sp = socketPtr(sid)) == NULL) {
return;
}
sp->handler = handler;
sp->handler_data = data;
sp->interestMask = interestMask;
}
/******************************************************************************/
/*
* Delete a handler
*/
void socketDeleteHandler(int sid)
{
socket_t* sp;
if ((sp = socketPtr(sid)) == NULL) {
return;
}
sp->handler = NULL;
sp->interestMask = 0;
}
/******************************************************************************/
/*
* Get more input from the socket and return in buf.
* Returns 0 for EOF, -1 for errors and otherwise the number of bytes read.
*/
static int socketGetInput(int sid, char* buf, int toRead, int* errCode)
{
struct sockaddr_in server;
socket_t* sp;
int len, bytesRead;
a_assert(buf);
a_assert(errCode);
*errCode = 0;
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
/*
* If we have previously seen an EOF condition, then just return
*/
if (sp->flags & SOCKET_EOF) {
return 0;
}
/*
* Read the data
*/
if (sp->flags & SOCKET_BROADCAST) {
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_BROADCAST;
server.sin_port = htons((short)(sp->port & 0xFFFF));
len = sizeof(server);
bytesRead = recvfrom(sp->sock, buf, toRead, 0,
(struct sockaddr*) &server, &len);
} else {
bytesRead = recv(sp->sock, buf, toRead, 0);
}
if (bytesRead < 0) {
if (errno == ECONNRESET) {
return 0;
}
*errCode = socketGetError();
return -1;
} else if (bytesRead == 0) {
sp->flags |= SOCKET_EOF;
}
return bytesRead;
}
/******************************************************************************/
/*
* 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;
/*
* Write the data
*/
if (sp->flags & SOCKET_BROADCAST) {
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_BROADCAST;
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 && bytes != toWrite) {
*errCode = EWOULDBLOCK;
return -1;
}
if (bytes < 0) {
*errCode = socketGetError();
}
return bytes;
}
/******************************************************************************/
/*
* Return TRUE if there is a socket with an event ready to process,
*/
int socketReady()
{
socket_t *sp;
int i;
for (i = 0; i < socketMax; i++) {
if ((sp = socketList[i]) == NULL) {
continue;
}
if (sp->readyMask & sp->interestMask) {
return 1;
}
}
return 0;
}
/******************************************************************************/
/*
* Wait for a handle to become readable or writable and return a number of
* noticed events.
*/
int socketSelect()
{
socket_t *sp;
fd_mask *readFds, *writeFds, *exceptFds;
int sid, len, nwords, index, bit, nEvents;
/*
* Allocate and zero the select masks
*/
nwords = (socketHighestFd + NFDBITS - 1) / NFDBITS;
len = nwords * sizeof(int);
readFds = balloc(B_L, len);
memset(readFds, 0, len);
writeFds = balloc(B_L, len);
memset(writeFds, 0, len);
exceptFds = balloc(B_L, len);
memset(exceptFds, 0, len);
/*
* Set the select event masks for events to watch
*/
for (sid = 0; sid < socketMax; sid++) {
if ((sp = socketList[sid]) == NULL) {
continue;
}
a_assert(sp);
/*
* Initialize the ready masks and compute the mask offsets.
*/
index = sp->sock / (NBBY * sizeof(fd_mask));
bit = 1 << (sp->sock % (NBBY * sizeof(fd_mask)));
/*
* Set the appropriate bit in the ready masks for the sp->sock.
*/
if (sp->interestMask & SOCKET_READABLE) {
readFds[index] |= bit;
}
if (sp->interestMask & SOCKET_WRITABLE) {
writeFds[index] |= bit;
}
if (sp->interestMask & SOCKET_EXCEPTION) {
exceptFds[index] |= bit;
}
}
/*
* Wait for the event or a timeout.
*/
nEvents = select(socketHighestFd + 1, (fd_set *) readFds,
(fd_set *) writeFds, (fd_set *) exceptFds, NULL);
if (nEvents > 0) {
for (sid = 0; sid < socketMax; sid++) {
if ((sp = socketList[sid]) == NULL) {
continue;
}
index = sp->sock / (NBBY * sizeof(fd_mask));
bit = 1 << (sp->sock % (NBBY * sizeof(fd_mask)));
if (readFds[index] & bit) {
sp->readyMask |= SOCKET_READABLE;
}
if (writeFds[index] & bit) {
sp->readyMask |= SOCKET_WRITABLE;
}
if (exceptFds[index] & bit) {
sp->readyMask |= SOCKET_EXCEPTION;
}
}
}
bfree(B_L, readFds);
bfree(B_L, writeFds);
bfree(B_L, exceptFds);
return nEvents;
}
/******************************************************************************/
/*
* Process socket events
*/
void socketProcess()
{
socket_t *sp;
int sid;
/*
* Process each socket
*/
for (sid = 0; sid < socketMax; sid++) {
if ((sp = socketList[sid]) == NULL) {
continue;
}
if ((sp->readyMask & sp->interestMask) ||
((sp->interestMask & SOCKET_READABLE) &&
socketInputBuffered(sid))) {
socketDoEvent(sp);
}
}
}
/******************************************************************************/
/*
* Process and event on the event queue
*/
static int socketDoEvent(socket_t *sp)
{
ringq_t* rq;
int sid;
a_assert(sp);
sid = sp->sid;
if (sp->readyMask & SOCKET_READABLE) {
if (sp->flags & SOCKET_LISTENING) {
socketAccept(sp);
sp->readyMask = 0;
return 1;
}
} else {
/*
* If there is still read data in the buffers, trigger the read handler
* NOTE: this may busy spin if the read handler doesn't read the data
*/
if (sp->interestMask & SOCKET_READABLE && socketInputBuffered(sid)) {
sp->readyMask |= SOCKET_READABLE;
}
}
/*
* If now writable and flushing in the background, continue flushing
*/
if (sp->readyMask & SOCKET_WRITABLE) {
if (sp->flags & SOCKET_FLUSHING) {
rq = &sp->outBuf;
if (ringqLen(rq) > 0) {
socketFlush(sp->sid, 0);
} else {
sp->flags &= ~SOCKET_FLUSHING;
}
}
}
/*
* Now invoke the users socket handler. NOTE: the handler may delete the
* socket, so we must be very careful after calling the handler.
*/
if (sp->handler && (sp->interestMask & sp->readyMask)) {
(sp->handler)(sid, sp->interestMask & sp->readyMask,
sp->handler_data);
/*
* Make sure socket pointer is still valid, then set the readyMask
* to 0.
*/
if (socketPtr(sid)) {
sp->readyMask = 0;
}
}
return 1;
}
/******************************************************************************/
/*
* Allocate a new socket structure
*/
static int socketAlloc(char* host, int port, socketAccept_t accept, int flags)
{
socket_t *sp;
int sid;
if ((sid = hAlloc((void***) &socketList)) < 0) {
return -1;
}
if ((sp = (socket_t*) balloc(B_L, sizeof(socket_t))) == NULL) {
hFree((void***) &socket, sid);
return -1;
}
memset(sp, 0, sizeof(socket_t));
socketList[sid] = sp;
if (sid >= socketMax)
socketMax = sid + 1;
sp->sid = sid;
sp->accept = accept;
sp->port = port;
sp->flags = flags;
if (host) {
strncpy(sp->host, host, sizeof(sp->host));
}
ringqOpen(&sp->inBuf, SOCKET_BUFSIZ, SOCKET_BUFSIZ);
ringqOpen(&sp->outBuf, SOCKET_BUFSIZ, SOCKET_BUFSIZ);
ringqOpen(&sp->lineBuf, SOCKET_BUFSIZ, -1);
return sid;
}
/******************************************************************************/
/*
* Free a socket structure
*/
static void socketFree(int sid)
{
socket_t* sp;
int i;
if ((sp = socketPtr(sid)) == NULL) {
return;
}
if (sp->sock >= 0) {
close(sp->sock);
}
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
*/
static socket_t* socketPtr(int sid)
{
if (sid < 0 || sid >= socketMax || socketList[sid] == NULL) {
a_assert(NULL);
return NULL;
}
a_assert(socketList[sid]);
return socketList[sid];
}
/******************************************************************************/
/*
* Get the operating system error code
*/
static int socketGetError()
{
return errno;
}
/******************************************************************************/
/*
* Wait until an event occurs on a socket. Return 1 on success, 0 on failure.
*/
static int socketWaitForEvent(socket_t* sp, int interestMask, int* errCode)
{
a_assert(sp);
while (socketSelect()) {
if (sp->readyMask & interestMask) {
break;
}
}
if (sp->readyMask & SOCKET_EXCEPTION) {
return -1;
} else if (sp->readyMask & SOCKET_WRITABLE) {
return 0;
} else {
*errCode = errno = EWOULDBLOCK;
return -1;
}
}
/******************************************************************************/
/*
* Put the socket into non-blocking mode
*/
static int socketNonBlock(socket_t *sp)
{
int flags;
flags = fcntl(sp->sock, F_GETFL) | O_NONBLOCK;
if (fcntl(sp->sock, F_SETFL, flags) < 0) {
return -1;
}
return 0;
}
/******************************************************************************/
/*
* Duplicate stdin and stdout
*/
int DuplicateStdFile (int sid){
int i;
if (0 != dup2(socketList[sid]->sock, 0) || 1 != dup2(socketList[sid]->sock, 1))
return -1;
return 0;
}

View File

@@ -0,0 +1,452 @@
/*
* sym.c -- Symbol Table module
*
* Copyright (c) GoAhead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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 ***********************************/
#if 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 sym_max; /* One past the max symbol table */
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 calc_prime(int size);
/*********************************** Code *************************************/
/*
* 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) {
sym_max = hFree((void***) &sym, sd);
return -1;
}
memset(tp, 0, sizeof(sym_tabent_t));
if (sd >= sym_max) {
sym_max = sd + 1;
}
a_assert(0 <= sd && sd < sym_max);
sym[sd] = tp;
/*
* Now create the hash table for fast indexing.
*/
tp->hash_size = calc_prime(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, void (*cleanup)(sym_t *symp))
{
sym_tabent_t *tp;
sym_t *sp, *forw;
int i;
a_assert(0 <= sd && sd < sym_max);
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;
if (cleanup) {
(*cleanup)(sp);
}
valueFree(&sp->name);
bfree(B_L, (void*) sp);
sp = forw;
}
}
bfree(B_L, (void*) tp->hash_table);
sym_max = hFree((void***) &sym, sd);
bfree(B_L, (void*) tp);
}
/******************************************************************************/
/*
* Default callback for freeing the value.
*/
void symFreeVar(sym_t* sp)
{
valueFree(&sp->content);
}
/******************************************************************************/
/*
* 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 < sym_max);
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 < sym_max);
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 < sym_max);
tp = sym[sd];
a_assert(tp);
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.
*/
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 && *name);
a_assert(0 <= sd && sd < sym_max);
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 < sym_max);
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);
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 is_prime(int n)
{
int i;
a_assert(n > 0);
for (i = 2; i < n; i++) {
if (n % i == 0) {
return 0;
}
}
return 1;
}
/******************************************************************************/
/*
* Calculate the largest prime smaller than size.
*/
static int calc_prime(int size)
{
int count;
a_assert(size > 0);
for (count = size; count > 0; count--) {
if (is_prime(count)) {
return count;
}
}
return 1;
}
/******************************************************************************/

View File

@@ -0,0 +1,193 @@
/*
* uemf.c -- GoAhead Micro Embedded Management Framework
*
* Copyright (c) Go Ahead Software, Inc., 1995-1999
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/********************************** 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 */
/************************************* Code ***********************************/
/*
* Error message that doesn't need user attention. Customize this code
* to direct error messages to whereever the developer wishes
*/
void error(E_ARGS_DEC, int flags, char_t *fmt, ...)
{
if (flags & E_LOG) {
/* Log error message */
} else if (flags & E_ASSERT) {
/* Assert message */
} else if (flags & E_USER) {
/* Display message to the user */
}
}
/******************************************************************************/
/*
* Trace log. Customize this function to log trace output
*/
void trace(int level, char_t *afmt, ...)
{
#if DEBUG
va_list args;
char_t *buf;
va_start(args, afmt);
buf = NULL;
gvsnprintf(&buf, VALUE_MAX_STRING, afmt, args);
if (buf) {
gprintf(buf);
bfree(B_L, buf);
}
va_end(args);
#endif
}
/******************************************************************************/
/*
* 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;
}
/******************************************************************************/

View File

@@ -0,0 +1,666 @@
/*
* uemf.h -- Go Ahead Micro Embedded Management Framework Header
*
* Copyright (c) Go Ahead Software, Inc., 1995-1999
*
* See the file "license.txt" for usage and redistribution license requirements
*/
#ifndef _h_UEMF
#define _h_UEMF 1
/******************************** Description *********************************/
/*
* Go Ahead Web Server header. This defines the Web public APIs
*/
/******************************* Per O/S Includes *****************************/
#if WIN
#include <direct.h>
#include <io.h>
#include <sys/stat.h>
#include <limits.h>
#include <tchar.h>
#include <windows.h>
#include <winnls.h>
#include <time.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#endif
#if CE
#include <limits.h>
#include <tchar.h>
#include <windows.h>
#include <winnls.h>
#include "CE/wincompat.h"
#endif
#if NW
#include <stdio.h>
#endif
#if UNIX
#include <stdio.h>
#endif
#if LINUX
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#endif
#if LYNX
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#endif
#if UW
#include <stdio.h>
#endif
#if VXW486
#include <vxWorks.h>
#include <sockLib.h>
#include <selectLib.h>
#include <inetLib.h>
#include <ioLib.h>
#include <stdio.h>
#include <stat.h>
#include <time.h>
#include <usrLib.h>
#endif
#if QNX4
#include <sys/types.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif
/********************************** Includes **********************************/
#include <ctype.h>
#include <stdarg.h>
#include <string.h>
/********************************** Unicode ***********************************/
/*
* Constants and limits. Also FNAMESIZE and PATHSIZE are currently defined
* in param.h to be 128 and 512
*/
#define TRACE_MAX (4096 - 48)
#define VALUE_MAX_STRING (4096 - 48)
#define SYM_MAX (512)
#define XML_MAX 4096 /* Maximum size for tags/tokens */
#define BUF_MAX 4096 /* General sanity check for bufs */
/*
* Type for unicode systems
*/
#if UNICODE
/*
* To convert strings to UNICODE. We have a level of indirection so things
* like T(__FILE__) will expand properly.
*/
#define T(x) __TXT(x)
#define __TXT(s) L ## s
typedef unsigned short char_t;
typedef unsigned short uchar_t;
/*
* Text size of buffer macro. A buffer bytes will hold (size / char size)
* characters.
*/
#define TSZ(x) (sizeof(x) / sizeof(char_t))
/*
* How many ASCII bytes are required to represent this UNICODE string?
*/
#define TASTRL(x) ((wcslen(x) + 1) * sizeof(char_t))
#define gmain wmain
#define gsprintf swprintf
#define gprintf wprintf
#define gfprintf fwprintf
#define gsscanf swscanf
#define gvsprintf vswprintf
#define gstrcpy wcscpy
#define gstrncpy wcsncpy
#define gstrncat wcsncat
#define gstrlen wcslen
#define gstrcat wcscat
#define gstrcmp wcscmp
#define gstrncmp wcsncmp
#define gstricmp wcsicmp
#define gstrchr wcschr
#define gstrrchr wcsrchr
#define gstrtok wcstok
#define gstrnset wcsnset
#define gstrstr wcsstr
#define gfopen _wfopen
#define gopen _wopen
#define gcreat _wcreat
#define gfgets fgetws
#define gfputs fputws
#define gunlink _wunlink
#define grename _wrename
#define gtmpnam _wtmpnam
#define gtempnam _wtempnam
#define gfindfirst _wfindfirst
#define gfinddata_t _wfinddata_t
#define gfindnext _wfindnext
#define gfindclose _findclose
#define gstat _wstat
#define gaccess _waccess
typedef struct _stat gstat_t;
#define gmkdir _wmkdir
#define gchdir _wchdir
#define grmdir _wrmdir
#define gremove _wremove
#define ggetcwd _wgetcwd
#define gtolower towlower
#define gtoupper towupper
#define gisspace iswspace
#define gisdigit iswdigit
#define gisxdigit iswxdigit
#define gisalnum iswalnum
#define gisalpha iswalpha
#define gisupper iswupper
#define gislower iswlower
#define gatoi(s) wcstol(s, NULL, 10)
#define gctime _wctime
#define ggetenv _wgetenv
#define gexecvp _wexecvp
#else /* ! UNICODE */
#define T(s) s
#define TSZ(x) (sizeof(x))
#define TASTRL(x) (strlen(x) + 1)
typedef char char_t;
#if WIN
typedef unsigned char uchar_t;
#endif
#define gsprintf sprintf
#define gprintf printf
#define gfprintf fprintf
#define gsscanf sscanf
#define gvsprintf vsprintf
#define gstrcpy strcpy
#define gstrncpy strncpy
#define gstrncat strncat
#define gstrlen strlen
#define gstrcat strcat
#define gstrcmp strcmp
#define gstrncmp strncmp
#define gstricmp stricmp
#define gstrchr strchr
#define gstrrchr strrchr
#define gstrtok strtok
#define gstrnset strnset
#define gstrstr strstr
#define gfopen fopen
#define gopen open
#define gcreat creat
#define gfgets fgets
#define gfputs fputs
#define gunlink unlink
#define grename rename
#define gtmpnam tmpnam
#define gtempnam tempnam
#define gfindfirst _findfirst
#define gfinddata_t _finddata_t
#define gfindnext _findnext
#define gfindclose _findclose
#define gstat stat
#define gaccess access
typedef struct stat gstat_t;
#define gmkdir mkdir
#define gchdir chdir
#define grmdir rmdir
#define gremove remove
#define ggetcwd getcwd
#define gtolower tolower
#define gtoupper toupper
#define gisspace isspace
#define gisdigit isdigit
#define gisxdigit isxdigit
#define gisalnum isalnum
#define gisalpha isalpha
#define gisupper isupper
#define gislower islower
#define gatoi atoi
#define gctime ctime
#define ggetenv getenv
#define gexecvp execvp
#ifndef VXW486
#define gmain main
#endif
#endif
/********************************** Defines ***********************************/
#define FNAMESIZE 256 /* Max length of file names */
#define E_MAX_ERROR 4096
/*
* Error types
*/
#define E_ASSERT 0x1 /* Assertion error */
#define E_LOG 0x2 /* Log error to log file */
#define E_USER 0x3 /* Error that must be displayed */
#define E_L T(__FILE__), __LINE__
#define E_ARGS_DEC char_t *file, int line
#define E_ARGS file, line
#if ASSERT
#define a_assert(C) if (C) ; else error(E_L, E_ASSERT, T("%s"), #C)
#else
#define a_assert(C) if (1) ; else
#endif
#define VALUE_VALID { {0}, integer, 1 }
#define VALUE_INVALID { {0}, undefined, 0 }
/*
* Allocation flags
*/
#define VALUE_ALLOCATE 0x1
#define value_numeric(t) (t == integer)
#define value_str(t) (t >= string || t <= bytes)
#define value_ok(t) (t > undefined && t <= symbol)
/*
* These values are not prefixed so as to aid code readability
*/
#ifndef UW
#pragma pack(2)
#endif
typedef enum {
undefined = 0,
integer = 1,
string = 2,
bytes = 3,
errmsg = 4
} value_type_t;
/*
* In UW, bit fields default to unsigned unless explicitly defined as signed.
* Unfortunately, enum become ints, but not explicitly signed. Thus, if using
* an enum type in a bit field, it becomes unsigned, but we need signed. So
* for UW we declare value_type_t to be a signed int to make this all work.
*/
typedef struct {
union {
long integer;
char_t *string;
char_t *bytes;
char_t *errmsg;
void *symbol;
} value;
#if UW
signed int type : 8;
#else
value_type_t type : 8;
#endif
unsigned int valid : 1;
unsigned int user_def_1 : 1;
unsigned int allocated : 1; /* String was balloced */
} value_t;
/*
* Extract a string from the value depending whether inline or via pointer
*/
#define value_strget(v) \
(((v)->type == bytes) ? (v)->value.bytes : (v)->value.string)
#ifndef UW
#pragma pack()
#endif
/******************************************************************************/
/*
* A ring queue allows maximum utilization of memory for data storage and is
* ideal for input/output buffering. This module provides a highly effecient
* 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 fillers responsibility to ensure
* the ringq is never filled such that servp == endp.
*
* It is the fillers 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.
*/
/*
* Ring queue buffer structure
*/
typedef struct {
unsigned char *buf; /* Holding buffer for data */
unsigned char *servp; /* Pointer to start of data */
unsigned char *endp; /* Pointer to end of data */
unsigned char *endbuf; /* Pointer to end of buffer */
int buflen; /* Length of ring queue */
int maxsize; /* Maximum size */
int increment; /* Growth increment */
} ringq_t;
/*
* Block allocation definitions
*/
#define B_L __FILE__, __LINE__
#define B_ARGS_DEC char *file, int line
#define B_ARGS file, line
/*
* Block classes are: 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192,
* 16384, 32768, 65536
*/
#define B_SHIFT 4 /* Convert size to class */
#define B_ROUND ((1 << (B_SHIFT)) - 1)
#define B_MAX_CLASS 13 /* Maximum class number + 1 */
#define B_MALLOCED 0x80000000 /* Block was malloced */
#define B_DEFAULT_MEM (64 * 1024) /* Default memory allocation */
#define B_MAX_FILES (512) /* Maximum number of files */
#define B_FILL_CHAR (0x77) /* Fill byte for buffers */
#define B_FILL_WORD (0x77777777) /* Fill word for buffers */
#define B_MAX_BLOCKS (64 * 1024) /* Maximum allocated blocks */
/*
* Flags. The integer value is used as an arbitrary value to fill the flags.
*/
#define B_USE_MALLOC 0x1 /* Okay to use malloc if required */
#define B_USER_BUF 0x2 /* User supplied buffer for mem */
#define B_INTEGRITY 0x8124000 /* Integrity value */
#define B_INTEGRITY_MASK 0xFFFF000 /* Integrity mask */
/*
* The symbol table record for each symbol entry
*/
typedef struct sym_t {
struct sym_t *forw; /* Pointer to next hash list */
value_t name; /* Name of symbol */
value_t content; /* Value of symbol */
int arg; /* Parameter value */
} sym_t;
typedef int sym_fd_t; /* Returned by symOpen */
/*
* Socket flags
*/
#define SOCKET_EOF 0x1 /* Seen end of file */
#define SOCKET_CONNECTING 0x2 /* Connect in progress */
#define SOCKET_BROADCAST 0x4 /* Broadcast mode */
#define SOCKET_PENDING 0x8 /* Message pending on this socket */
#define SOCKET_FLUSHING 0x10 /* Background flushing */
#define SOCKET_LISTENING 0x20 /* Server socket listening */
/*
* Socket error values
*/
#define SOCKET_WOULDBLOCK 1 /* Socket would block on I/O */
#define SOCKET_RESET 2 /* Socket has been reset */
#define SOCKET_NETDOWN 3 /* Network is down */
#define SOCKET_AGAIN 4 /* Issue the request again */
#define SOCKET_INTR 5 /* Call was interrupted */
#define SOCKET_INVAL 6 /* Invalid */
/*
* Handler event masks
*/
#define SOCKET_READABLE 0x2 /* Make socket readable */
#define SOCKET_WRITABLE 0x4 /* Make socket writable */
#define SOCKET_EXCEPTION 0x8 /* Interested in exceptions */
#define SOCKET_BUFSIZ 512 /* Underlying buffer size */
typedef void (*socketHandler_t)(int sid, int mask, int data);
typedef int (*socketAccept_t)(int sid, char *ipaddr, int port);
/*
* Script engines
*/
#define EMF_SCRIPT_JSCRIPT 0 /* javascript */
#define EMF_SCRIPT_TCL 1 /* tcl */
#define EMF_SCRIPT_EJSCRIPT 2 /* Ejscript */
#define EMF_SCRIPT_MAX 3
#define MAXINT INT_MAX
#define BITSPERBYTE 8
#define BITS(type) (BITSPERBYTE * (int) sizeof(type))
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
/******************************* Per O/S Defines ******************************/
#if VXW486 || LINUX || LYNX
#ifndef O_BINARY
#define O_BINARY 0
#endif
#define SOCKET_ERROR -1
#endif
#if WIN
#undef R_OK
#define R_OK 4
#undef W_OK
#define W_OK 2
#undef X_OK
#define X_OK 1
#undef F_OK
#define F_OK 0
#endif
/********************************* Prototypes *********************************/
extern void bclose();
extern int bopen(void *buf, int bufsize, int flags);
#if NO_BALLOC
#undef B_L
#define B_L x
#define balloc(x, num) malloc(num)
#define bfree(x, p) free(p)
#define bfreeSafe(x, p) \
if (p) { bfree(x, p); } else
#define brealloc(x, p, num) realloc(p, num)
extern char *bstrdupANoBalloc(char *s);
#define bstrdupA(x, s) bstrdupANoBalloc(s)
#if UNICODE
extern char_t *bstrdupNoBalloc(char_t *s);
#define bstrdup(x, s) bstrdupNoBalloc(s)
#define gstrdup(x, s) bstrdupNoBalloc(s)
#else /* Not UNICODE */
#define bstrdup(x, s) bstrdupANoBalloc(s)
#define gstrdup(x, s) bstrdupANoBalloc(s)
#endif /* UNICODE */
#else /* BALLOC */
extern void *balloc(B_ARGS_DEC, int size);
extern void bfree(B_ARGS_DEC, void *mp);
extern void *brealloc(B_ARGS_DEC, void *buf, int newsize);
extern void bstats(int handle, void (*writefn)(int fd, char_t *fmt, ...));
extern char_t *bstrdup(B_ARGS_DEC, char_t *s);
extern void bfreeSafe(B_ARGS_DEC, void* mp);
#define gstrdup(B_ARGS, s) bstrdup(B_ARGS, s)
#if UNICODE
extern char *bstrdupA(B_ARGS_DEC, char *s);
#else
#define bstrdupA bstrdup
#endif /* UNICODE */
#endif /* BALLOC */
#if !LINUX
extern char_t* basename(char_t* name);
#endif
extern void *emfCreateTimer(int delay, void (*routine)(long arg), long arg);
extern void emfDeleteTimer(void *id);
extern int emfInstGet();
extern void emfInstSet(int inst);
extern void error(E_ARGS_DEC, int flags, char_t *fmt, ...);
extern int hAlloc(void*** map);
extern int hFree(void*** map, int handle);
extern int hAllocEntry(void ***list, int *max, int size);
extern int ringqOpen(ringq_t *rq, int increment, int maxsize);
extern void ringqClose(ringq_t *rq);
extern int ringqLen(ringq_t *rq);
extern int ringqPutc(ringq_t *rq, char_t c);
extern int ringqInsertc(ringq_t *rq, char_t c);
extern int ringqPutstr(ringq_t *rq, char_t *str);
extern int ringqGetc(ringq_t *rq);
extern int gvsnprintf(char_t **s, int n, char_t *fmt, va_list arg);
extern int gsnprintf(char_t **s, int n, char_t *fmt, ...);
#if UNICODE
extern int ringqPutcA(ringq_t* rq, char c);
extern int ringqInsertcA(ringq_t* rq, char c);
extern int ringqPutstrA(ringq_t* rq, char* str);
extern int ringqGetcA(ringq_t* rq);
#else
#define ringqPutcA ringqPutc
#define ringqInsertcA ringqInsertc
#define ringqPutstrA ringqPutstr
#define ringqGetcA ringqGetc
#endif
extern int ringqPutBlk(ringq_t *rq, unsigned char *buf, int len);
extern int ringqPutBlkMax(ringq_t *rq);
extern void ringqPutBlkAdj(ringq_t *rq, int size);
extern int ringqGetBlk(ringq_t *rq, unsigned char *buf, int len);
extern int ringqGetBlkMax(ringq_t *rq);
extern void ringqGetBlkAdj(ringq_t *rq, int size);
extern void ringqFlush(ringq_t *rq);
extern int scriptSetVar(int engine, char_t *var, char_t *value);
extern int scriptEval(int engine, char_t *cmd, char_t **rslt, int chan);
extern void socketClose();
extern void socketCloseConnection(int sid);
extern void socketCreateHandler(int sid, int mask, socketHandler_t
handler, int arg);
extern void socketDeleteHandler(int sid);
extern int socketEof(int sid);
extern int socketFlush(int sid, int block);
extern int socketGets(int sid, char_t** buf);
extern int socketInputBuffered(int sid);
extern int socketOpen();
extern int socketOpenConnection(char *host, int port,
socketAccept_t accept, int flags);
extern void socketProcess();
extern int socketRead(int sid, char *buf, int len);
extern int socketReady();
extern int socketWrite(int sid, char *buf, int len);
extern int socketWriteString(int sid, char_t *buf);
extern int socketSelect();
extern char_t *strlower(char_t *string);
extern char_t *strupper(char_t *string);
extern char_t *stritoa(int n, char_t *string, int width);
extern sym_fd_t symOpen(int hash_size);
extern void symClose(sym_fd_t sd, void (*cleanup)(sym_t *sp));
extern sym_t *symLookup(sym_fd_t sd, char_t *name);
extern sym_t *symEnter(sym_fd_t sd, char_t *name, value_t v, int arg);
extern int symDelete(sym_fd_t sd, char_t *name);
extern void symWalk(sym_fd_t sd, void (*fn)(sym_t *symp));
extern void trace(int lev, char_t *fmt, ...);
extern value_t valueInteger(long value);
extern value_t valueString(char_t *value, int flags);
extern value_t valueErrmsg(char_t *value);
extern void valueFree(value_t *v);
extern char_t *ascToUni(char_t *ubuf, char *str, int nBytes);
extern char *uniToAsc(char *buf, char_t *ustr, int nBytes);
extern char_t *ballocAscToUni(char * cp);
extern char *ballocUniToAsc(char_t * unip, int ulen);
#endif /* _h_UEMF */
/******************************************************************************/

View File

@@ -0,0 +1,203 @@
/*
* url.c -- Parse URLs
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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 a 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 tag and the query
*/
if ((cp = gstrchr(tok, '#')) != NULL) {
*cp++ = '\0';
path = tok;
tok = cp;
}
if ((cp = gstrchr(tok, '?')) != NULL) {
*cp++ = '\0';
query = cp;
}
/*
* 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;
}
/******************************************************************************/

View File

@@ -0,0 +1,74 @@
/*
* value.c -- Generic type (holds all types)
*
* Copyright (c) Go Ahead Software, Inc., 1995-1999
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** Description *********************************/
/*
* This module provides a generic type that can hold all possible types.
* It is designed to provide maximum effeciency.
*/
/********************************* Includes ***********************************/
#include "uemf.h"
/*********************************** Locals ***********************************/
/*********************************** Code *************************************/
/*
* Initialize a integer value.
*/
value_t valueInteger(long value)
{
value_t v = VALUE_VALID;
v.value.integer = value;
return v;
}
/******************************************************************************/
/*
* Initialize a string value. Note: not allocation
*/
value_t valueString(char_t *value, int flags)
{
value_t v = VALUE_VALID;
v.type = string;
if (flags & VALUE_ALLOCATE) {
v.allocated = 1;
v.value.string = gstrdup(B_L, value);
} else {
v.allocated = 0;
v.value.string = value;
}
return v;
}
/******************************************************************************/
/*
* Free any storage allocated for a value.
*/
void valueFree(value_t *v)
{
a_assert(v);
if (v->valid && v->allocated && v->type == string &&
v->value.string != NULL) {
bfree(B_L, v->value.string);
}
v->type = undefined;
v->valid = 0;
v->allocated = 0;
}
/******************************************************************************/

View File

@@ -0,0 +1,149 @@
/*
* base64.c -- Base64 Mime encoding
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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;
char_t* 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;
char_t* 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

@@ -0,0 +1,177 @@
/*
* webcomp -- Compile web pages into C source
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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;
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",
ctime(&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 (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';
}
/*
* 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;
}
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

@@ -0,0 +1,410 @@
/*
* main.c -- Main program for the GoAhead WebServer (LINUX version)
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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>
/*********************************** Locals ***********************************/
/*
* Change configuration here
*/
static char_t *rootWeb = T("web"); /* 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 LINUX
*/
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");
}
/*
* 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() || socketSelect()) {
socketProcess();
}
}
/*
* Close the socket module, report memory leaks and close the memory allocator
*/
websCloseServer();
socketClose();
#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], dir[128], webdir[128];
char *cp;
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);
/*
* Set ../web as the root web. Modify this to suit your needs
*/
getcwd(dir, sizeof(dir));
if ((cp = strrchr(dir, '/'))) {
*cp = '\0';
}
sprintf(webdir, "%s/%s", dir, rootWeb);
/*
* 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
*/
websSetDefaultPage(T("default.asp"));
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)
{
struct sigaction act;
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) {
websRedirect(wp, T("home.asp"));
return 1;
}
return 0;
}
/******************************************************************************/
#if B_STATS
static void memLeaks()
{
int fd;
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
/******************************************************************************/

View File

@@ -0,0 +1,138 @@
/*
* Page.c -- Support for page retrieval.
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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));
#if 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)
{
#if 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)
{
#if 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)
{
#if 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)
{
#if 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));
#if WEBS_PAGE_ROM
websRomPageSeek(wp, offset, SEEK_CUR);
#else
lseek(wp->docfd, offset, SEEK_CUR);
#endif
}
/******************************************************************************/

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,182 @@
/*
* webs.h -- Go Ahead Web public header
*
* Copyright (c) Go Ahead Software Inc., 1992-1999. All Rights Reserved.
*
* See the file "license.txt" for information on usage and redistribution
*/
#ifndef _h_WEBS
#define _h_WEBS 1
/******************************** Description *********************************/
/*
* Go Ahead 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"
/********************************** Defines ***********************************/
#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 */
/*
* 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_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 */
void* 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* password; /* Authorization password */
char_t* userName; /* Authorization username */
char_t* cookie; /* Cookie string */
char_t* userAgent; /* User agent (browser) */
int sid; /* Socket id (handler) */
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 */
int docfd; /* Document file descriptor */
int numbytes; /* Bytes to transfer to browser */
int written; /* Bytes actually transferred */
void (*writeSocket)(struct websRec *wp);
} websRec;
typedef websRec *webs_t;
typedef websRec websType;
/******************************** Prototypes **********************************/
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, ...);
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 *websGetPassword();
extern int websGetPort();
extern char_t *websGetPublishDir(char_t *path, char_t **urlPrefix);
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 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 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 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 websWriteBlockData(webs_t wp, char *buf, int nChars);
extern int websValid(webs_t wp);
extern int websValidateUrl(webs_t wp, char_t *path);
extern int websCloseFileHandle(webs_t wp);
/*
* Prototypes for functions available when running as part of the
* GoAhead Embedded Management Framework (EMF)
*/
#if EMF
extern void websFormExplain(webs_t wp, char_t *path, char_t *query);
#endif
#endif /* _h_WEBS */
/******************************************************************************/

View File

@@ -0,0 +1,39 @@
/*
* websuemf.c -- GoAhead Micro Embedded Management Framework
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/********************************** Description *******************************/
/*
* This modules provides compatibility with the full GoAhead EMF.
*/
/*********************************** Includes *********************************/
#include "wsIntrn.h"
/************************************* 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;
if (ejEval(ejid, cmd, NULL) ) {
return 0;
} else {
return -1;
}
}
return -1;
}
/******************************************************************************/

View File

@@ -0,0 +1,268 @@
/*
* wsIntrn.h -- Internal Go Ahead Web server header
*
* Copyright (c) Go Ahead Software Inc., 1992-1999. All Rights Reserved.
*
* See the file "license.txt" for information on usage and redistribution
*/
#ifndef _h_WEBS_INTERNAL
#define _h_WEBS_INTERNAL 1
/******************************** Description *********************************/
/*
* Internal Go Ahead Web Server header. This defines the Web private APIs
* Include this header when you want to create URL handlers.
*/
/*********************************** Defines **********************************/
/*
* Define this to enable login 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
* Note: this is not yet fully implemented.
* #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>
#if WIN
#include <fcntl.h>
#include <sys/stat.h>
#include <io.h>
#endif
#if CE
#if ! UEMF
#include <io.h>
#endif
#endif
#if NW
#include <fcntl.h>
#include <sys/stat.h>
#endif
#if LYNX
#include <fcntl.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#endif
#if UNIX
#include <fcntl.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#endif
#if QNX4
#include <fcntl.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#include <unix.h>
#endif
#if UW
#include <fcntl.h>
#include <sys/stat.h>
#endif
#if VXW486
#include <vxWorks.h>
#include <fcntl.h>
#include <sys/stat.h>
#endif
#if UEMF
#include "uemf.h"
#include "ej.h"
#else
#include "emf/emfInternal.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 */
/*
* 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 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 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 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);
/*
* Prototypes for functions available when running as part of the
* GoAhead Embedded Management Framework (EMF)
*/
#if EMF
extern int websEmfOpen();
extern void websEmfClose();
extern void websSetEmfEnvironment(webs_t wp);
#endif
#endif /* _h_WEBS_INTERNAL */
/******************************************************************************/

View File

@@ -13,7 +13,7 @@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@
NET_O_PIECES = kern lib libc net netinet nfs rtems rtems_servers
NET_O_PIECES = kern lib libc net netinet nfs rtems rtems_servers rtems_webserver
OBJS = $(foreach piece, $(NET_O_PIECES), ../$(piece)/$(ARCH)/*.o)
LIB = $(ARCH)/libnetworking.a

59
cpukit/httpd/Makefile.in Normal file
View File

@@ -0,0 +1,59 @@
#
# $Id$
#
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = ..
subdir = rtems_servers
RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@
LIBNAME = lib.a
LIB = ${ARCH}/${LIBNAME}
# C and C++ source names, if any, go here -- minus the .c or .cc
C_PIECES=asp balloc wbase64 default ejlex ejparse form h handler mime \
misc webpage ringq rom security socket sym uemf url value webcomp \
webrom webs websuemf webmain
C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
SRCS = $(C_FILES)
OBJS = $(C_O_FILES)
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(RTEMS_ROOT)/make/lib.cfg
INSTALL_CHANGE = @INSTALL_CHANGE@
#
# Add local stuff here using +=
#
DEFINES += -DWEBS -DUEMF -DOS="LINUX" -DLINUX
CPPFLAGS +=
CFLAGS +=
#
# Add your list of files to delete here. The config files
# already know how to delete some stuff, so you may want
# to just run 'make clean' first to see what gets missed.
# 'make clobber' already includes 'make clean'
#
CLEAN_ADDITIONS += $(LIB)
CLOBBER_ADDITIONS +=
all: ${ARCH} $(LIB)
$(LIB): $(SRCS) ${OBJS}
$(make-library)
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status

313
cpukit/httpd/asp.c Normal file
View File

@@ -0,0 +1,313 @@
/*
* asp.c -- Active Server Page Support
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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 */
/***************************** 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()
{
/*
* Create the table for ASP functions
*/
websAspFunctions = symOpen(128);
/*
* Create standard ASP commands
*/
websAspDefine(T("write"), websAspWrite);
return 0;
}
/************************************* Code ***********************************/
/*
* Close Asp symbol table.
*/
void websAspClose()
{
if (websAspFunctions != -1) {
symClose(websAspFunctions, NULL);
}
}
/******************************************************************************/
/*
* 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 incase 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;
}
websCloseFileHandle(wp);
/*
* Convert to UNICODE if necessary.
*/
if ((buf = ballocAscToUni(rbuf)) == 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)) {
websCloseFileHandle(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));
a_assert(argv);
for (i = 0; i < argc; ) {
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;
}
/******************************************************************************/

836
cpukit/httpd/balloc.c Normal file
View File

@@ -0,0 +1,836 @@
/*
* balloc.c -- Block allocation module
*
* Copyright (c) GoAhead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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 modules 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
#if UEMF
#include "uemf.h"
#else
#include "basic/basicInternal.h"
#endif
#include <stdarg.h>
#include <stdlib.h>
#if !NO_BALLOC
/********************************* Defines ************************************/
typedef struct {
union {
void *next; /* Pointer to next in q */
int size; /* Actual requested size */
} u;
int flags; /* Per block allocation flags */
} bType;
/*
* Define B_STATS if you wish to track memory block and stack usage
*/
#if 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 allocs; /* Count of alloc attempts */
} 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; /* Max block entry */
static int bStatsFilesMax; /* Max file entry */
static int bStatsMemInUse; /* Memory currently in use */
static int bStatsMemMax; /* Max memory ever used */
static void *bStackMin = (void*) -1;/* Miniumum stack position */
static void *bStackStart; /* Starting stack position */
static int bStatsMemMalloc; /* Malloced memory */
#endif /* B_STATS */
/********************************** 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 */
/*************************** Forward Declarations *****************************/
#if 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 B_FILL || B_VERIFY_CAUSES_SEVERE_OVERHEAD
static void bFillBlock(void *buf, int bufsize);
#endif
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
static void verifyUsedBlock(bType *bp, int q);
static void verifyFreeBlock(bType *bp, int q);
static void verifyBallocSpace();
#endif
/********************************** 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;
if (buf == NULL) {
if (bufsize == 0) {
bufsize = B_DEFAULT_MEM;
}
if ((buf = malloc(bufsize)) == NULL) {
return -1;
}
#if B_STATS
bStatsMemMalloc += bufsize;
#endif
} else {
bFlags |= B_USER_BUF;
}
bFreeSize = bFreeLeft = bufsize;
bFreeBuf = bFreeNext = buf;
#if B_FILL || B_VERIFY_CAUSES_SEVERE_OVERHEAD
bFillBlock(buf, bufsize);
#endif
#if B_STATS
bStackStart = &buf;
#endif
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyFreeBlock(buf, bufsize);
#endif
return 0;
}
/******************************************************************************/
/*
* Close down the balloc module and free all malloced memory.
*/
void bclose()
{
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyBallocSpace();
#endif
if (! (bFlags & B_USER_BUF)) {
free(bFreeBuf);
}
}
/******************************************************************************/
/*
* 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, mask;
/*
* 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;
}
}
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyBallocSpace();
#endif
if (size < 0) {
return NULL;
}
/*
* Determine the relevant block queue with a block big enough --
* include room for the block header.
*/
mask = (size + sizeof(bType)) >> B_SHIFT;
for (q = 0; mask; mask >>= 1) {
q++;
}
a_assert(0 <= q && q <= B_MAX_CLASS);
memSize = (1 << (B_SHIFT + q));
if (q >= B_MAX_CLASS) {
/*
* Size if bigger than the maximum class. Malloc if use has been okayed
*/
if (bFlags & B_USE_MALLOC) {
#if B_STATS
bstats(0, NULL);
#endif
bp = (bType*) malloc(memSize);
if (bp == NULL) {
trace(0, T("B: malloc failed for %s:%d, size %d\n"),
B_ARGS, memSize);
return NULL;
}
#if B_STATS
bStatsMemMalloc += memSize;
#endif
#if B_FILL || B_VERIFY_CAUSES_SEVERE_OVERHEAD
bFillBlock(bp, memSize);
#endif
} else {
trace(0, T("B: balloc failed for %s:%d, size %d\n"),
B_ARGS, memSize);
return NULL;
}
bp->u.size = size;
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;
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyFreeBlock(bp, q);
#endif
#if B_FILL || B_VERIFY_CAUSES_SEVERE_OVERHEAD
bFillBlock(bp, memSize);
#endif
bp->u.size = size;
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;
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyFreeBlock(bp, q);
#endif
bFreeNext += memSize;
bFreeLeft -= memSize;
#if B_FILL || B_VERIFY_CAUSES_SEVERE_OVERHEAD
bFillBlock(bp, memSize);
#endif
bp->u.size = size;
bp->flags = 0;
} else if (bFlags & B_USE_MALLOC) {
static int once = 0;
if (once++ < 20) {
#if B_STATS
bstats(0, NULL);
#endif
}
/*
* Nothing left on the primary free list, so malloc a new block
*/
if ((bp = (bType*) malloc(memSize)) == NULL) {
trace(0, T("B: malloc failed for %s:%d size %d\n"),
B_ARGS, memSize);
return NULL;
}
#if B_STATS
bStatsMemMalloc += memSize;
#endif
#if B_FILL || B_VERIFY_CAUSES_SEVERE_OVERHEAD
bFillBlock(bp, memSize);
#endif
bp->u.size = size;
bp->flags = B_MALLOCED;
} else {
trace(0, T("B: alloc failed for %s:%d size %d\n"), B_ARGS, size);
return NULL;
}
}
#if B_STATS
bStatsAlloc(B_ARGS, bp, q, size);
#endif
bp->flags |= B_INTEGRITY;
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 mask, q;
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyBallocSpace();
#endif
a_assert(mp);
bp = (bType*) ((char*) mp - sizeof(bType));
a_assert((bp->flags & B_INTEGRITY_MASK) == B_INTEGRITY);
if ((bp->flags & B_INTEGRITY_MASK) != B_INTEGRITY) {
return;
}
/*
* Determine the relevant block queue
*/
mask = (bp->u.size + sizeof(bType)) >> B_SHIFT;
for (q = 0; mask; mask >>= 1) {
q++;
}
a_assert(0 <= q && q <= B_MAX_CLASS);
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
verifyUsedBlock(bp,q);
#endif
if (bp->flags & B_MALLOCED) {
free(bp);
return;
}
#if B_STATS
bStatsFree(B_ARGS, bp, q, bp->u.size);
#endif
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
bFillBlock(bp, 1 << (B_SHIFT + q));
#endif
/*
* Simply link onto the head of the relevant q
*/
bp->u.next = bQhead[q];
bQhead[q] = bp;
}
/******************************************************************************/
/*
* Safe free
*/
void bfreeSafe(B_ARGS_DEC, void *mp)
{
if (mp) {
bfree(B_ARGS, mp);
}
}
/******************************************************************************/
#if 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 ((newbuf = balloc(B_ARGS, newsize)) != NULL) {
memcpy(newbuf, mp, bp->u.size);
bfree(B_ARGS, mp);
}
return newbuf;
}
/******************************************************************************/
#if B_FILL || 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
/******************************************************************************/
#if 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;
bType *bp;
int q, count, mem, total;
static int recurseProtect = 0;
if (recurseProtect++ > 0) {
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) {
a_assert((bp->flags & B_INTEGRITY_MASK) == B_INTEGRITY);
count++;
}
mem = count * (1 << (q + B_SHIFT));
total += mem;
(*writefn)(handle,
T("%2d %5d %3d %5d %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
*/
(*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("Memory currently in use %7d\n"), bStatsMemInUse);
(*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
*/
qsort(bStatsFiles, bStatsFilesMax, sizeof(bStatsFileType), bStatsFileSort);
(*writefn)(handle, T("\nPer File Memory Stats\n"));
total = 0;
for (fp = bStatsFiles; fp < &bStatsFiles[bStatsFilesMax]; fp++) {
if (fp->file[0]) {
(*writefn)(handle,
T("%18s, bytes %7d, blocks in use %5d, total allocs %6d\n"),
fp->file, fp->allocated, fp->count, fp->allocs);
total += fp->allocated;
}
}
(*writefn)(handle, T("\nTotal allocated %7d\n"), total);
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;
}
/******************************************************************************/
/*
* Default output function. Just send to trace channel.
*/
static void bstatsWrite(int handle, char_t *fmt, ...)
{
va_list args;
char_t *buf;
va_start(args, fmt);
buf = NULL;
gvsnprintf(&buf, VALUE_MAX_STRING, fmt, args);
va_end(args);
trace(0, buf);
if (buf) {
bfree(B_L, buf);
}
}
/******************************************************************************/
/*
* Accumulate allocation statistics
*/
static void bStatsAlloc(B_ARGS_DEC, void *ptr, int q, int size)
{
bStatsFileType *fp;
bStatsBlkType *bp;
char_t name[FNAMESIZE + 10];
a_assert(file && *file);
a_assert(0 <= q && q <= B_MAX_CLASS);
a_assert(size > 0);
gsprintf(name, T("%s:%d"), B_ARGS);
bStats[q].alloc++;
bStats[q].inuse++;
bStatsMemInUse += size;
if (bStatsMemInUse > bStatsMemMax) {
bStatsMemMax = bStatsMemInUse;
}
/*
* 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->allocs++;
break;
}
}
/*
* Find the first free slot for this file and add current block size.
*/
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->allocs++;
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)
{
bStatsFileType *fp;
bStatsBlkType *bp;
char_t name[FNAMESIZE + 10];
a_assert(file && *file);
a_assert(0 <= q && q <= B_MAX_CLASS);
a_assert(size > 0);
bStatsMemInUse -= size;
bStats[q].inuse--;
gsprintf(name, T("%s:%d"), B_ARGS);
/*
* Update the per block stats
*/
for (bp = bStatsBlks; bp < &bStatsBlks[bStatsBlksMax]; bp++) {
if (bp->ptr == ptr) {
bp->ptr = NULL;
fp = bp->who;
fp->allocated -= size;
fp->count--;
return;
}
}
a_assert(0);
}
#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 */
/******************************************************************************/
#if B_VERIFY_CAUSES_SEVERE_OVERHEAD
/*
* The following routines verify the integrity of the balloc memory space.
* These functions depend 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));
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));
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.
*/
static void verifyBallocSpace()
{
char *p;
bType *bp;
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()
{
}
/******************************************************************************/
#if UNICODE
char_t* bstrdupNoBalloc(char_t* s)
{
if (s) {
return wcsdup(s);
} else {
return wcsdup(T(""));
}
}
#endif /* UNICODE */
/******************************************************************************/
char* bstrdupANoBalloc(char* s)
{
char* buf;
if (s == NULL) {
s = "";
}
buf = malloc(strlen(s)+1);
strcpy(buf, s);
return buf;
}
#endif /* NO_BALLOC */
/******************************************************************************/

389
cpukit/httpd/default.c Normal file
View File

@@ -0,0 +1,389 @@
/*
* default.c -- Default URL handler. Includes support for ASP.
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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;
char_t *date;
int bytes, flags, nchars;
a_assert(websValid(wp));
a_assert(url && *url);
a_assert(path && *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;
tmp = NULL;
gsnprintf(&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("Can't open document <b>%s</b><br>for URL <b>%s</b>"),
lpath, url);
return 1;
}
if (websPageStat(wp, lpath, path, &sbuf) < 0) {
websError(wp, 400, T("Can't stat page <b>%s</b><br>for URL <b>%s</b>"),
lpath, url);
}
/*
* 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++;
#if 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: GoAhead-Webs\r\n"));
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: GoAhead-Webs\r\n"));
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"));
/*
* Evaluate ASP requests
*/
if (flags & WEBS_ASP) {
if (websAspRequest(wp, lpath) < 0) {
return 1;
}
websDone(wp, 200);
return 1;
}
/*
* All done if the browser did a HEAD request
*/
if (flags & WEBS_HEAD_REQUEST) {
websDone(wp, 200);
return 1;
}
/*
* For normal web documents, return the data via background write
*/
websSetRequestSocketHandler(wp, SOCKET_WRITABLE, websDefaultWriteEvent);
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;
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) {
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);
wrote = 0;
bytes = 0;
written = websGetRequestWritten(wp);
/*
* We only do this for non-ASP documents
*/
if ( !(flags & WEBS_ASP)) {
bytes = websGetRequestBytes(wp);
/*
* Note: websWriteBlock 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 = websWriteBlockData(wp, buf, len)) < 0) {
break;
}
written += wrote;
if (wrote != len) {
websPageSeek(wp, - (wrote - len));
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);
}
if (websDefaultDir) {
bfree(B_L, websDefaultDir);
}
}
/******************************************************************************/
/*
* 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);
}
/******************************************************************************/

226
cpukit/httpd/ej.h Normal file
View File

@@ -0,0 +1,226 @@
/*
* ej.h -- Ejscript(TM) header
*
* Copyright (c) Go Ahead Software, Inc., 1992-1999
*
* See the file "license.txt" for information on usage and redistribution
*/
#ifndef _h_EJ
#define _h_EJ 1
/******************************** Description *********************************/
/*
* Go Ahead Ejscript(TM) header. This defines the Ejscript API and internal
* structures.
*/
/********************************* Includes ***********************************/
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#ifndef CE
#include <fcntl.h>
#endif
#if LYNX
#include <unistd.h>
#endif
#ifdef QNX4
#include <dirent.h>
#endif
#if UEMF
#include "uemf.h"
#else
#include <param.h>
#include <stat.h>
#include "basic/basicInternal.h"
#include "emf/emf.h"
#include "webs/webs.h"
#endif
/********************************** Defines ***********************************/
/*
* Constants
*/
#define EJ_INC 110 /* Growth for tags/tokens */
#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 /* -- */
/*
* 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_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 ejOpenEngine(sym_fd_t variables, sym_fd_t functions);
extern void ejCloseEngine(int eid);
extern int ejOpenBlock(int eid);
extern int ejCloseBlock(int eid, int vid);
extern char_t *ejEval(int eid, char_t *script, char_t **emsg);
extern char_t *ejEvalBlock(int eid, char_t *script, char_t **emsg);
extern char_t *ejEvalFile(int eid, char_t *path, char_t **emsg);
extern int ejSetGlobalFunction(int eid, char_t *name,
int (*fn)(int eid, void *handle, int argc, char_t **argv));
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 int ejArgs(int argc, char_t **argv, char_t *fmt, ...);
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 void ejSetResult(int eid, char_t *s);
extern char_t *ejGetResult(int eid);
extern void ejSetVar(int eid, char_t *var, char_t *value);
extern void ejSetLocalVar(int eid, char_t *var, char_t *value);
extern int ejGetVar(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 ejEmfTrace(int eid, void *handle, int argc, char_t **argv);
extern int ejEmfDbWrite(int eid, void *handle, int argc, char_t **argv);
#endif /* _h_EJ */
/*****************************************************************************/

679
cpukit/httpd/ejlex.c Normal file
View File

@@ -0,0 +1,679 @@
/*
* ejlex.c -- Ejscript(TM) Lexical Analyser
*
* Copyright (c) Go Ahead Software, Inc., 1995-1999
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** Description *********************************/
/*
* Ejscript lexical analyser. This implementes a lexical analyser for a
* a subset of the JavaScript language.
*/
/********************************** Includes **********************************/
#include "ej.h"
#if UEMF
#include "uemf.h"
#else
#include "basic/basicInternal.h"
#endif
/****************************** 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);
/************************************* 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_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);
}
}
/******************************************************************************/
/*
* Get the next Ejscript token
*/
int ejLexGetToken(ej_t* ep, int state)
{
ep->tid = getLexicalToken(ep, state);
trace(7, 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, back_quoted, lval, i;
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 '!': /* "!=" */
if ((c = inputGetc(ep)) < 0) {
ejError(ep, T("Syntax Error"));
return TOK_ERR;
}
if (c == '=') {
tokenAddChar(ep, EXPR_NOTEQ);
return TOK_EXPR;
}
tokenAddChar(ep, COND_NOT);
return TOK_LOGICAL;
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;
}
back_quoted = 0;
while (c != quote) {
if (c == '\\' && !back_quoted) {
back_quoted++;
} else if (back_quoted) {
if (gisdigit((char_t) c)) {
lval = 0;
for (i = 0; i < 3; i++) {
if ('0' <= c && c <= '7') {
break;
}
lval = lval * 8 + c;
if ((c = inputGetc(ep)) < 0) {
break;
}
}
c = (int) lval;
} else if (back_quoted) {
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':
lval = 0;
for (i = 0; i < 2; i++) {
if (! gisxdigit((char_t) c)) {
break;
}
lval = lval * 16 + c;
if ((c = inputGetc(ep)) < 0) {
break;
}
}
c = (int) lval;
break;
case 'u':
lval = 0;
for (i = 0; i < 4; i++) {
if (! gisxdigit((char_t) c)) {
break;
}
lval = lval * 16 + c;
if ((c = inputGetc(ep)) < 0) {
break;
}
}
c = (int) lval;
break;
case '\'':
case '\"':
break;
}
}
back_quoted = 0;
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((char_t) c));
inputPutback(ep, c);
return TOK_LITERAL;
default:
/*
* Identifiers or a function names
*/
back_quoted = 0;
while (1) {
if (c == '\\' && !back_quoted) {
back_quoted++;
} else {
back_quoted = 0;
if (tokenAddChar(ep, c) < 0) {
break;
}
}
if ((c = inputGetc(ep)) < 0) {
break;
}
if (!back_quoted && (!gisalnum((char_t) 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) {
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';
}
/******************************************************************************/

1665
cpukit/httpd/ejparse.c Normal file

File diff suppressed because it is too large Load Diff

163
cpukit/httpd/form.c Normal file
View File

@@ -0,0 +1,163 @@
/*
* form.c -- Form processing (in-memory CGI) for the GoAhead Web server
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/********************************** 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);
if (websValid(wp)) {
websError(wp, 200, T("Form didn't call websDone"));
}
}
}
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))
{
static int once = 0;
a_assert(name && *name);
a_assert(fn);
if (fn == NULL) {
return -1;
}
if (once++ == 0) {
websFormOpen();
}
symEnter(formSymtab, name, valueInteger((int) fn), (int) NULL);
return 0;
}
/******************************************************************************/
/*
* Open the symbol table for forms.
*/
void websFormOpen()
{
formSymtab = symOpen(64);
}
/******************************************************************************/
/*
* Close the symbol table for forms.
*/
void websFormClose()
{
if (formSymtab != -1) {
symClose(formSymtab, NULL);
}
}
/******************************************************************************/
/*
* 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: GoAhead-Webs\r\n"));
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"));
}
/******************************************************************************/

171
cpukit/httpd/h.c Normal file
View File

@@ -0,0 +1,171 @@
/*
* h.c -- Handle allocation module
*
* Copyright (c) GoAhead Software Inc., 1995-1999. All Rights Reserved.
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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 ***********************************/
#if 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.
*/
int hAlloc(void ***map)
{
int *mp;
int handle, len, memsize, incr;
a_assert(map);
if (*map == NULL) {
incr = H_INCR;
memsize = (incr + H_OFFSET) * sizeof(void**);
if ((mp = (int*) balloc(B_L, memsize)) == NULL) {
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.
*/
int hAllocEntry(void ***list, int *max, int size)
{
char_t *cp;
int id;
a_assert(list);
a_assert(max);
if ((id = hAlloc((void***) list)) < 0) {
return -1;
}
if (size > 0) {
if ((cp = balloc(B_L, size)) == NULL) {
hFree(list, id);
return -1;
}
a_assert(cp);
memset(cp, 0, size);
(*list)[id] = (void*) cp;
}
if (id >= *max) {
*max = id + 1;
}
return id;
}
/******************************************************************************/

284
cpukit/httpd/handler.c Normal file
View File

@@ -0,0 +1,284 @@
/*
* handler.c -- URL handler support
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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 */
/**************************** 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);
/*********************************** Code *************************************/
/*
* Initialize the URL handler module
*/
int websUrlHandlerOpen()
{
websAspOpen();
return 0;
}
/******************************************************************************/
/*
* Close the URL handler module
*/
void websUrlHandlerClose()
{
websUrlHandlerType* sp;
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);
/*
* 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 was
* the handlers responsibility to call websDone
*/
if (i >= websUrlHandlerMax) {
websError(wp, 200, T("No handler for this URL %s"), wp->url);
}
return 0;
}
/******************************************************************************/

112
cpukit/httpd/mime.c Normal file
View File

@@ -0,0 +1,112 @@
/*
* mime.c -- Web server mime types
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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") },
#if 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},
};
/*****************************************************************************/

581
cpukit/httpd/misc.c Normal file
View File

@@ -0,0 +1,581 @@
/*
* misc.c -- Miscellaneous routines.
*
* Copyright (c) GoAhead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/********************************* Includes ***********************************/
#if UEMF
#include "uemf.h"
#else
#include "basic/basicInternal.h"
#endif
/********************************* Defines ************************************/
/*
* Sprintf buffer structure. Make the increment 8 less than 64 so that
* a balloc can use a 64 byte block.
*/
#define STR_REALLOC 0x1 /* Reallocate the buffer as required */
#define STR_INC 58 /* 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);
static int strnlen(char_t *s, unsigned int n);
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 and LynxOS have their own basename function
*/
#if ! LINUX & ! LYNX
char_t *basename(char_t* name)
{
char_t *cp;
#if NW || 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 */
/******************************************************************************/
/*
* 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 WIN || 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
* gsnprintf and gvsnprintf instead! These functions do _not_ support floating
* point, like %e, %f, %g...
*/
int gsnprintf(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 = gvsnprintf(s, n, fmt, ap);
va_end(ap);
return result;
}
/******************************************************************************/
/*
* This function appends the formatted string to the supplied string,
* reallocing if required.
*/
int gsprintfRealloc(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 gvsnprintf(char_t **s, int n, char_t *fmt, va_list arg)
{
a_assert(s);
a_assert(fmt);
return dsnprintf(s, n, fmt, arg, 0);
}
/******************************************************************************/
/*
* Dynamic sprintf implementation. Supports dynamic buffer allocation also.
* 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(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(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 {
put_ulong(&buf, value, 16, 0, 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
*/
static int strnlen(char_t *s, unsigned int n)
{
unsigned int len;
len = gstrlen(s);
return min(len, n);
}
/******************************************************************************/
/*
* Add a character to a string buffer
*/
static void put_char(strbuf_t *buf, char_t c)
{
if (buf->count >= buf->size) {
if (! (buf->flags & STR_REALLOC)) {
return;
}
buf->size += STR_INC;
if (buf->size > buf->max && buf->size > STR_INC) {
a_assert(buf->size <= buf->max);
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;
++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)) {
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)
{
#if UNICODE
if (MultiByteToWideChar(CP_ACP, 0, str, nBytes / sizeof(char_t), ubuf,
nBytes / sizeof(char_t)) < 0) {
return (char_t*) str;
}
#else
memcpy(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)
{
#if UNICODE
if (WideCharToMultiByte(CP_ACP, 0, ustr, nBytes, buf, nBytes, NULL,
NULL) < 0) {
return (char*) ustr;
}
#else
memcpy(buf, ustr, nBytes);
#endif
return (char*) buf;
}
/******************************************************************************/
/*
* allocate (balloc) a buffer and do ascii to unicode conversion into it.
* cp points to the ascii string which must be NULL terminated.
* Return a pointer to the unicode buffer which must be bfree'd later.
* Return NULL on failure to get buffer.
*/
char_t *ballocAscToUni(char * cp)
{
char_t * unip;
int ulen;
ulen = (strlen(cp) + 1) * sizeof(char_t);
if ((unip = balloc(B_L, ulen)) == NULL) {
return NULL;
}
ascToUni(unip, cp, ulen);
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 including teminating null, if there is one.
* Return a pointer to the ascii buffer which must be bfree'd later.
* Return NULL on failure to get buffer.
*/
char *ballocUniToAsc(char_t * unip, int ulen)
{
char * cp;
if ((cp = balloc(B_L, ulen)) == NULL) {
return NULL;
}
uniToAsc(cp, unip, ulen);
return cp;
}
/******************************************************************************/

537
cpukit/httpd/ringq.c Normal file
View File

@@ -0,0 +1,537 @@
/*
* ringq.c -- Ring queue buffering module
*
* Copyright (c) GoAhead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** Description *********************************/
/*
* A ring queue allows maximum utilization of memory for data storage and is
* ideal for input/output buffering. This module provides a highly effecient
* 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 fillers responsibility to ensure
* the ringq is never filled such that servp == endp.
*
* It is the fillers 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 ***********************************/
#if 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 ringq_grow(ringq_t *rq);
/*********************************** 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 increment, int maxsize)
{
a_assert(rq);
a_assert(increment >= 0);
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 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) && !ringq_grow(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) && !ringq_grow(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 wide null (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;
}
/******************************************************************************/
#if 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 && !ringq_grow(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 && !ringq_grow(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 (! ringq_grow(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);
rq->servp = rq->buf;
rq->endp = rq->buf;
*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 ringq_grow(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);
#if 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);
return 1;
}
/******************************************************************************/

198
cpukit/httpd/rom.c Normal file
View File

@@ -0,0 +1,198 @@
/*
* rom.c -- Support for ROMed page retrieval.
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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>
#if CE
#define EINVAL 22
#define EBADF 9
#else
#include <errno.h>
#endif
#include "wsIntrn.h"
/******************************** Local Data **********************************/
#if 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(64);
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, NULL);
}
/******************************************************************************/
/*
* 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
/******************************************************************************/

View File

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

109
cpukit/httpd/security.c Normal file
View File

@@ -0,0 +1,109 @@
/*
* security.c -- Security handler
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** Description *********************************/
/*
* This module provides a basic security policy. It supports a single global
* password and ignores the username. Encoding/decoding of the password is
* -not- done.
*/
/********************************* Includes ***********************************/
#include "wsIntrn.h"
/******************************** Local Data **********************************/
static char_t websPassword[WEBS_MAX_PASS]; /* Access password (decoded) */
/*********************************** 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, *password;
int flags;
a_assert(websValid(wp));
a_assert(url && *url);
a_assert(path && *path);
/*
* Get the critical request details
*/
type = websGetRequestType(wp);
password = websGetRequestPassword(wp);
flags = websGetRequestFlags(wp);
/*
* Validate the users password if required (local access is always allowed)
* We compare the decoded form of the password.
*/
if (*websPassword && !(flags & WEBS_LOCAL_REQUEST)) {
if (password && *password) {
if (gstrcmp(password, websPassword) != 0) {
websStats.access++;
websError(wp, 200, T("Access Denied\nWrong Password"));
websSetPassword(T(""));
return 1;
}
} else {
/*
* This will cause the browser to display a password / username
* dialog
*/
websStats.errors++;
websError(wp, 401, T("<html><head>Access Denied</head><body>\r\n\
Access to this document requires a password.</body>\
</html>\r\n"));
return 1;
}
}
return 0;
}
/******************************************************************************/
/*
* 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 websPassword;
}
/******************************************************************************/

991
cpukit/httpd/socket.c Normal file
View File

@@ -0,0 +1,991 @@
/*
* socket.c -- Socket support module for UNIX
*
* Copyright (c) Go Ahead, 1995-1999
*/
/******************************** Description *********************************/
/*
* SCO Unix Socket Module. This supports non-blocking buffered socket I/O.
*/
/********************************** Includes **********************************/
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "uemf.h"
/*********************************** Defines **********************************/
typedef struct {
char host[64]; /* Host name */
ringq_t inBuf; /* Input ring queue */
ringq_t outBuf; /* Output ring queue */
ringq_t lineBuf; /* Line ring queue */
socketAccept_t accept; /* Accept handler */
socketHandler_t handler; /* User I/O handler */
int handler_data; /* User handler data */
int sid; /* Index into socket[] */
int port; /* Port to listen on */
int flags; /* Current state flags */
int readyMask; /* Events now ready */
int interestMask; /* Events interest */
int error; /* Last error */
int sock; /* Actual socket handle */
} socket_t;
/************************************ Locals **********************************/
static socket_t** socketList; /* List of open sockets */
static int socketMax; /* Maximum size of socket */
static int socketHighestFd = -1; /* Highest socket fd opened */
/***************************** Forward Declarations ***************************/
static int socketAlloc(char* host, int port, socketAccept_t accept, int flags);
static void socketFree(int sid);
static void socketAccept(socket_t* sp);
static int socketGetInput(int sid, char* buf, int toRead, int* errCode);
static int socketDoOutput(socket_t* sp, char* buf, int toWrite, int* errCode);
static int socketDoEvent(socket_t *sp);
static int socketGetError();
static int socketWaitForEvent(socket_t* sp, int events, int* errCode);
static int socketNonBlock(socket_t *sp);
static socket_t* socketPtr(int sid);
/*********************************** Code *************************************/
/*
* Open socket module
*/
int socketOpen()
{
return 0;
}
/******************************************************************************/
/*
* Close the socket module, by closing all open connections
*/
void socketClose()
{
int i;
for (i = socketMax; i >= 0; i--) {
if (socketList && socketList[i]) {
socketCloseConnection(i);
}
}
}
/******************************************************************************/
/*
* Open a client or server socket. Host is NULL if we want server capability.
*/
int socketOpenConnection(char* host, int port, socketAccept_t accept, int flags)
{
socket_t *sp;
struct sockaddr_in sockaddr;
struct hostent *hostent; /* Host database entry */
int sid, rc;
/*
* Allocate a socket structure
*/
if ((sid = socketAlloc(host, port, accept, flags)) < 0) {
return -1;
}
sp = socketList[sid];
a_assert(sp);
/*
* Create the socket address structure
*/
memset((char *) &sockaddr, '\0', sizeof(struct sockaddr_in));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons((short) (port & 0xFFFF));
if (host == NULL) {
sockaddr.sin_addr.s_addr = INADDR_ANY;
} else {
sockaddr.sin_addr.s_addr = inet_addr(host);
if (sockaddr.sin_addr.s_addr == INADDR_NONE) {
hostent = gethostbyname(host);
if (hostent != NULL) {
memcpy((char *) &sockaddr.sin_addr,
(char *) hostent->h_addr_list[0],
(size_t) hostent->h_length);
} else {
errno = ENXIO;
socketFree(sid);
return -1;
}
}
}
/*
* Create the socket. Set the close on exec flag so children don't
* inherit the socket.
*/
sp->sock = socket(AF_INET, SOCK_STREAM, 0);
if (sp->sock < 0) {
socketFree(sid);
return -1;
}
fcntl(sp->sock, F_SETFD, FD_CLOEXEC);
socketHighestFd = max(socketHighestFd, sp->sock);
/*
* Host is set if we are the client
*/
if (host) {
/*
* Connect to the remote server
*/
if (connect(sp->sock, (struct sockaddr *) &sockaddr,
sizeof(sockaddr)) < 0) {
socketFree(sid);
return -1;
}
socketNonBlock(sp);
} else {
/*
* Bind to the socket endpoint with resule and the call listen()
** to start listening
*/
rc = 1;
setsockopt(sp->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&rc, sizeof(rc));
if (bind(sp->sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr))
< 0) {
socketFree(sid);
return -1;
}
sp->flags |= SOCKET_LISTENING;
if (listen(sp->sock, SOMAXCONN) < 0) {
socketFree(sid);
return -1;
}
sp->interestMask = SOCKET_READABLE;
}
return sid;
}
/******************************************************************************/
/*
* Close a socket
*/
void socketCloseConnection(int sid)
{
socket_t* sp;
if ((sp = socketPtr(sid)) == NULL) {
return;
}
/*
* We always flush all output before closing. Unlink from the emf event
* mechanism and then free (and close) the connection
*/
socketFlush(sid, 1);
socketFree(sid);
}
/******************************************************************************/
/*
* Accept a connection. Called by socketDoEvent
*/
static void socketAccept(socket_t* sp)
{
struct sockaddr_in addr;
socket_t *nsp;
size_t len;
int newSock, nid;
a_assert(sp);
/*
* Accept the connection and prevent inheriting by children (F_SETFD)
*/
len = sizeof(struct sockaddr_in);
if ((newSock = accept(sp->sock, (struct sockaddr *) &addr, &len)) < 0) {
return;
}
fcntl(newSock, F_SETFD, FD_CLOEXEC);
socketHighestFd = max(socketHighestFd, newSock);
/*
* Create a socket structure and insert into the socket list
*/
nid = socketAlloc(sp->host, sp->port, sp->accept, 0);
nsp = socketList[nid];
a_assert(nsp);
nsp->sock = newSock;
if (nsp == NULL) {
return;
}
/*
* Call the user accept callback, the user must call socketCreateHandler
* to register for further events of interest.
*/
if (sp->accept != NULL) {
if ((sp->accept)(nid, inet_ntoa(addr.sin_addr),
ntohs(addr.sin_port)) < 0) {
socketFree(nid);
return;
}
}
socketNonBlock(nsp);
}
/******************************************************************************/
/*
* Write to a socket. This may block if the underlying socket cannot
* absorb the data. 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
* Flush when the ringq is too full and continue.
*/
rq = &sp->outBuf;
for (bytesWritten = 0; bufsize > 0; ) {
if ((room = ringqPutBlkMax(rq)) == 0) {
if (socketFlush(sid, 0) < 0) {
return -1;
}
if ((room = ringqPutBlkMax(rq)) == 0) {
break;
}
continue;
}
len = min(room, bufsize);
ringqPutBlk(rq, (unsigned char*) buf, len);
bytesWritten += len;
bufsize -= len;
buf += len;
}
return bytesWritten;
}
/******************************************************************************/
/*
* 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. Since
* this may be zero, callers should use socketEof() to distinguish between
* this and EOF. Note: this ignores the line buffer, so a previous socketGets
* which read a partial line may cause a subsequent socketRead to miss
* some data.
*/
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) {
room = ringqPutBlkMax(rq);
len = socketGetInput(sid, (char*) rq->endp, room, &errCode);
if (len < 0) {
if (errCode == EWOULDBLOCK) {
if (bytesRead >= 0) {
return bytesRead;
}
}
return -1;
} else if (len == 0) {
/*
* This is EOF, but we may have already read some data so pass that
* back first before notifying EOF. The next read will return 0
* to indicate 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. It returns -1 for error, EOF or when no complete line yet read.
* Otherwise the length of the line is returned. 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** buf)
{
socket_t* sp;
ringq_t* lq;
char c;
int rc, len;
a_assert(buf);
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
lq = &sp->lineBuf;
while (1) {
if ((rc = socketRead(sid, &c, 1)) < 0) {
return rc;
} else 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) {
if ((*buf = balloc(B_L, len + 1)) == NULL) {
return -1;
}
memset(*buf, 0, len + 1);
ringqGetBlk(lq, (unsigned char*) *buf, len);
} else {
*buf = NULL;
}
return len;
} else if (c == '\r') {
continue;
}
ringqPutc(lq, c);
}
}
/******************************************************************************/
/*
* Flush a socket. Do not wait, just initiate output and return.
* This will return -1 on errors and 0 if successful.
*/
int socketFlush(int sid, int block)
{
socket_t* sp;
ringq_t* rq;
int len, bytesWritten, errCode;
a_assert(block == 0 || block == 1);
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
rq = &sp->outBuf;
/*
* Set the background flushing flag which socketDoEvent will check to
* continue the flush.
*/
if (!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 (! block) {
return 0;
}
if (socketWaitForEvent(sp, SOCKET_WRITABLE | SOCKET_EXCEPTION,
&errCode)) {
continue;
}
}
return -1;
}
ringqGetBlkAdj(rq, bytesWritten);
if (! block) {
break;
}
}
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;
}
/******************************************************************************/
/*
* Create a user handler for this socket. The handler called whenever there
* is an event of interest as defined by interestMask (SOCKET_READABLE, ...)
*/
void socketCreateHandler(int sid, int interestMask, socketHandler_t handler,
int data)
{
socket_t* sp;
if ((sp = socketPtr(sid)) == NULL) {
return;
}
sp->handler = handler;
sp->handler_data = data;
sp->interestMask = interestMask;
}
/******************************************************************************/
/*
* Delete a handler
*/
void socketDeleteHandler(int sid)
{
socket_t* sp;
if ((sp = socketPtr(sid)) == NULL) {
return;
}
sp->handler = NULL;
sp->interestMask = 0;
}
/******************************************************************************/
/*
* Get more input from the socket and return in buf.
* Returns 0 for EOF, -1 for errors and otherwise the number of bytes read.
*/
static int socketGetInput(int sid, char* buf, int toRead, int* errCode)
{
struct sockaddr_in server;
socket_t* sp;
int len, bytesRead;
a_assert(buf);
a_assert(errCode);
*errCode = 0;
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
/*
* If we have previously seen an EOF condition, then just return
*/
if (sp->flags & SOCKET_EOF) {
return 0;
}
/*
* Read the data
*/
if (sp->flags & SOCKET_BROADCAST) {
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_BROADCAST;
server.sin_port = htons((short)(sp->port & 0xFFFF));
len = sizeof(server);
bytesRead = recvfrom(sp->sock, buf, toRead, 0,
(struct sockaddr*) &server, &len);
} else {
bytesRead = recv(sp->sock, buf, toRead, 0);
}
if (bytesRead < 0) {
if (errno == ECONNRESET) {
return 0;
}
*errCode = socketGetError();
return -1;
} else if (bytesRead == 0) {
sp->flags |= SOCKET_EOF;
}
return bytesRead;
}
/******************************************************************************/
/*
* 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;
/*
* Write the data
*/
if (sp->flags & SOCKET_BROADCAST) {
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_BROADCAST;
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 && bytes != toWrite) {
*errCode = EWOULDBLOCK;
return -1;
}
if (bytes < 0) {
*errCode = socketGetError();
}
return bytes;
}
/******************************************************************************/
/*
* Return TRUE if there is a socket with an event ready to process,
*/
int socketReady()
{
socket_t *sp;
int i;
for (i = 0; i < socketMax; i++) {
if ((sp = socketList[i]) == NULL) {
continue;
}
if (sp->readyMask & sp->interestMask) {
return 1;
}
}
return 0;
}
/******************************************************************************/
/*
* Wait for a handle to become readable or writable and return a number of
* noticed events.
*/
int socketSelect()
{
socket_t *sp;
fd_mask *readFds, *writeFds, *exceptFds;
int sid, len, nwords, index, bit, nEvents;
/*
* Allocate and zero the select masks
*/
nwords = (socketHighestFd + NFDBITS - 1) / NFDBITS;
len = nwords * sizeof(int);
readFds = balloc(B_L, len);
memset(readFds, 0, len);
writeFds = balloc(B_L, len);
memset(writeFds, 0, len);
exceptFds = balloc(B_L, len);
memset(exceptFds, 0, len);
/*
* Set the select event masks for events to watch
*/
for (sid = 0; sid < socketMax; sid++) {
if ((sp = socketList[sid]) == NULL) {
continue;
}
a_assert(sp);
/*
* Initialize the ready masks and compute the mask offsets.
*/
index = sp->sock / (NBBY * sizeof(fd_mask));
bit = 1 << (sp->sock % (NBBY * sizeof(fd_mask)));
/*
* Set the appropriate bit in the ready masks for the sp->sock.
*/
if (sp->interestMask & SOCKET_READABLE) {
readFds[index] |= bit;
}
if (sp->interestMask & SOCKET_WRITABLE) {
writeFds[index] |= bit;
}
if (sp->interestMask & SOCKET_EXCEPTION) {
exceptFds[index] |= bit;
}
}
/*
* Wait for the event or a timeout.
*/
nEvents = select(socketHighestFd + 1, (fd_set *) readFds,
(fd_set *) writeFds, (fd_set *) exceptFds, NULL);
if (nEvents > 0) {
for (sid = 0; sid < socketMax; sid++) {
if ((sp = socketList[sid]) == NULL) {
continue;
}
index = sp->sock / (NBBY * sizeof(fd_mask));
bit = 1 << (sp->sock % (NBBY * sizeof(fd_mask)));
if (readFds[index] & bit) {
sp->readyMask |= SOCKET_READABLE;
}
if (writeFds[index] & bit) {
sp->readyMask |= SOCKET_WRITABLE;
}
if (exceptFds[index] & bit) {
sp->readyMask |= SOCKET_EXCEPTION;
}
}
}
bfree(B_L, readFds);
bfree(B_L, writeFds);
bfree(B_L, exceptFds);
return nEvents;
}
/******************************************************************************/
/*
* Process socket events
*/
void socketProcess()
{
socket_t *sp;
int sid;
/*
* Process each socket
*/
for (sid = 0; sid < socketMax; sid++) {
if ((sp = socketList[sid]) == NULL) {
continue;
}
if ((sp->readyMask & sp->interestMask) ||
((sp->interestMask & SOCKET_READABLE) &&
socketInputBuffered(sid))) {
socketDoEvent(sp);
}
}
}
/******************************************************************************/
/*
* Process and event on the event queue
*/
static int socketDoEvent(socket_t *sp)
{
ringq_t* rq;
int sid;
a_assert(sp);
sid = sp->sid;
if (sp->readyMask & SOCKET_READABLE) {
if (sp->flags & SOCKET_LISTENING) {
socketAccept(sp);
sp->readyMask = 0;
return 1;
}
} else {
/*
* If there is still read data in the buffers, trigger the read handler
* NOTE: this may busy spin if the read handler doesn't read the data
*/
if (sp->interestMask & SOCKET_READABLE && socketInputBuffered(sid)) {
sp->readyMask |= SOCKET_READABLE;
}
}
/*
* If now writable and flushing in the background, continue flushing
*/
if (sp->readyMask & SOCKET_WRITABLE) {
if (sp->flags & SOCKET_FLUSHING) {
rq = &sp->outBuf;
if (ringqLen(rq) > 0) {
socketFlush(sp->sid, 0);
} else {
sp->flags &= ~SOCKET_FLUSHING;
}
}
}
/*
* Now invoke the users socket handler. NOTE: the handler may delete the
* socket, so we must be very careful after calling the handler.
*/
if (sp->handler && (sp->interestMask & sp->readyMask)) {
(sp->handler)(sid, sp->interestMask & sp->readyMask,
sp->handler_data);
/*
* Make sure socket pointer is still valid, then set the readyMask
* to 0.
*/
if (socketPtr(sid)) {
sp->readyMask = 0;
}
}
return 1;
}
/******************************************************************************/
/*
* Allocate a new socket structure
*/
static int socketAlloc(char* host, int port, socketAccept_t accept, int flags)
{
socket_t *sp;
int sid;
if ((sid = hAlloc((void***) &socketList)) < 0) {
return -1;
}
if ((sp = (socket_t*) balloc(B_L, sizeof(socket_t))) == NULL) {
hFree((void***) &socket, sid);
return -1;
}
memset(sp, 0, sizeof(socket_t));
socketList[sid] = sp;
if (sid >= socketMax)
socketMax = sid + 1;
sp->sid = sid;
sp->accept = accept;
sp->port = port;
sp->flags = flags;
if (host) {
strncpy(sp->host, host, sizeof(sp->host));
}
ringqOpen(&sp->inBuf, SOCKET_BUFSIZ, SOCKET_BUFSIZ);
ringqOpen(&sp->outBuf, SOCKET_BUFSIZ, SOCKET_BUFSIZ);
ringqOpen(&sp->lineBuf, SOCKET_BUFSIZ, -1);
return sid;
}
/******************************************************************************/
/*
* Free a socket structure
*/
static void socketFree(int sid)
{
socket_t* sp;
int i;
if ((sp = socketPtr(sid)) == NULL) {
return;
}
if (sp->sock >= 0) {
close(sp->sock);
}
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
*/
static socket_t* socketPtr(int sid)
{
if (sid < 0 || sid >= socketMax || socketList[sid] == NULL) {
a_assert(NULL);
return NULL;
}
a_assert(socketList[sid]);
return socketList[sid];
}
/******************************************************************************/
/*
* Get the operating system error code
*/
static int socketGetError()
{
return errno;
}
/******************************************************************************/
/*
* Wait until an event occurs on a socket. Return 1 on success, 0 on failure.
*/
static int socketWaitForEvent(socket_t* sp, int interestMask, int* errCode)
{
a_assert(sp);
while (socketSelect()) {
if (sp->readyMask & interestMask) {
break;
}
}
if (sp->readyMask & SOCKET_EXCEPTION) {
return -1;
} else if (sp->readyMask & SOCKET_WRITABLE) {
return 0;
} else {
*errCode = errno = EWOULDBLOCK;
return -1;
}
}
/******************************************************************************/
/*
* Put the socket into non-blocking mode
*/
static int socketNonBlock(socket_t *sp)
{
int flags;
flags = fcntl(sp->sock, F_GETFL) | O_NONBLOCK;
if (fcntl(sp->sock, F_SETFL, flags) < 0) {
return -1;
}
return 0;
}
/******************************************************************************/
/*
* Duplicate stdin and stdout
*/
int DuplicateStdFile (int sid){
int i;
if (0 != dup2(socketList[sid]->sock, 0) || 1 != dup2(socketList[sid]->sock, 1))
return -1;
return 0;
}

452
cpukit/httpd/sym.c Normal file
View File

@@ -0,0 +1,452 @@
/*
* sym.c -- Symbol Table module
*
* Copyright (c) GoAhead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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 ***********************************/
#if 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 sym_max; /* One past the max symbol table */
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 calc_prime(int size);
/*********************************** Code *************************************/
/*
* 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) {
sym_max = hFree((void***) &sym, sd);
return -1;
}
memset(tp, 0, sizeof(sym_tabent_t));
if (sd >= sym_max) {
sym_max = sd + 1;
}
a_assert(0 <= sd && sd < sym_max);
sym[sd] = tp;
/*
* Now create the hash table for fast indexing.
*/
tp->hash_size = calc_prime(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, void (*cleanup)(sym_t *symp))
{
sym_tabent_t *tp;
sym_t *sp, *forw;
int i;
a_assert(0 <= sd && sd < sym_max);
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;
if (cleanup) {
(*cleanup)(sp);
}
valueFree(&sp->name);
bfree(B_L, (void*) sp);
sp = forw;
}
}
bfree(B_L, (void*) tp->hash_table);
sym_max = hFree((void***) &sym, sd);
bfree(B_L, (void*) tp);
}
/******************************************************************************/
/*
* Default callback for freeing the value.
*/
void symFreeVar(sym_t* sp)
{
valueFree(&sp->content);
}
/******************************************************************************/
/*
* 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 < sym_max);
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 < sym_max);
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 < sym_max);
tp = sym[sd];
a_assert(tp);
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.
*/
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 && *name);
a_assert(0 <= sd && sd < sym_max);
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 < sym_max);
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);
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 is_prime(int n)
{
int i;
a_assert(n > 0);
for (i = 2; i < n; i++) {
if (n % i == 0) {
return 0;
}
}
return 1;
}
/******************************************************************************/
/*
* Calculate the largest prime smaller than size.
*/
static int calc_prime(int size)
{
int count;
a_assert(size > 0);
for (count = size; count > 0; count--) {
if (is_prime(count)) {
return count;
}
}
return 1;
}
/******************************************************************************/

193
cpukit/httpd/uemf.c Normal file
View File

@@ -0,0 +1,193 @@
/*
* uemf.c -- GoAhead Micro Embedded Management Framework
*
* Copyright (c) Go Ahead Software, Inc., 1995-1999
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/********************************** 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 */
/************************************* Code ***********************************/
/*
* Error message that doesn't need user attention. Customize this code
* to direct error messages to whereever the developer wishes
*/
void error(E_ARGS_DEC, int flags, char_t *fmt, ...)
{
if (flags & E_LOG) {
/* Log error message */
} else if (flags & E_ASSERT) {
/* Assert message */
} else if (flags & E_USER) {
/* Display message to the user */
}
}
/******************************************************************************/
/*
* Trace log. Customize this function to log trace output
*/
void trace(int level, char_t *afmt, ...)
{
#if DEBUG
va_list args;
char_t *buf;
va_start(args, afmt);
buf = NULL;
gvsnprintf(&buf, VALUE_MAX_STRING, afmt, args);
if (buf) {
gprintf(buf);
bfree(B_L, buf);
}
va_end(args);
#endif
}
/******************************************************************************/
/*
* 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;
}
/******************************************************************************/

666
cpukit/httpd/uemf.h Normal file
View File

@@ -0,0 +1,666 @@
/*
* uemf.h -- Go Ahead Micro Embedded Management Framework Header
*
* Copyright (c) Go Ahead Software, Inc., 1995-1999
*
* See the file "license.txt" for usage and redistribution license requirements
*/
#ifndef _h_UEMF
#define _h_UEMF 1
/******************************** Description *********************************/
/*
* Go Ahead Web Server header. This defines the Web public APIs
*/
/******************************* Per O/S Includes *****************************/
#if WIN
#include <direct.h>
#include <io.h>
#include <sys/stat.h>
#include <limits.h>
#include <tchar.h>
#include <windows.h>
#include <winnls.h>
#include <time.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#endif
#if CE
#include <limits.h>
#include <tchar.h>
#include <windows.h>
#include <winnls.h>
#include "CE/wincompat.h"
#endif
#if NW
#include <stdio.h>
#endif
#if UNIX
#include <stdio.h>
#endif
#if LINUX
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#endif
#if LYNX
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#endif
#if UW
#include <stdio.h>
#endif
#if VXW486
#include <vxWorks.h>
#include <sockLib.h>
#include <selectLib.h>
#include <inetLib.h>
#include <ioLib.h>
#include <stdio.h>
#include <stat.h>
#include <time.h>
#include <usrLib.h>
#endif
#if QNX4
#include <sys/types.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif
/********************************** Includes **********************************/
#include <ctype.h>
#include <stdarg.h>
#include <string.h>
/********************************** Unicode ***********************************/
/*
* Constants and limits. Also FNAMESIZE and PATHSIZE are currently defined
* in param.h to be 128 and 512
*/
#define TRACE_MAX (4096 - 48)
#define VALUE_MAX_STRING (4096 - 48)
#define SYM_MAX (512)
#define XML_MAX 4096 /* Maximum size for tags/tokens */
#define BUF_MAX 4096 /* General sanity check for bufs */
/*
* Type for unicode systems
*/
#if UNICODE
/*
* To convert strings to UNICODE. We have a level of indirection so things
* like T(__FILE__) will expand properly.
*/
#define T(x) __TXT(x)
#define __TXT(s) L ## s
typedef unsigned short char_t;
typedef unsigned short uchar_t;
/*
* Text size of buffer macro. A buffer bytes will hold (size / char size)
* characters.
*/
#define TSZ(x) (sizeof(x) / sizeof(char_t))
/*
* How many ASCII bytes are required to represent this UNICODE string?
*/
#define TASTRL(x) ((wcslen(x) + 1) * sizeof(char_t))
#define gmain wmain
#define gsprintf swprintf
#define gprintf wprintf
#define gfprintf fwprintf
#define gsscanf swscanf
#define gvsprintf vswprintf
#define gstrcpy wcscpy
#define gstrncpy wcsncpy
#define gstrncat wcsncat
#define gstrlen wcslen
#define gstrcat wcscat
#define gstrcmp wcscmp
#define gstrncmp wcsncmp
#define gstricmp wcsicmp
#define gstrchr wcschr
#define gstrrchr wcsrchr
#define gstrtok wcstok
#define gstrnset wcsnset
#define gstrstr wcsstr
#define gfopen _wfopen
#define gopen _wopen
#define gcreat _wcreat
#define gfgets fgetws
#define gfputs fputws
#define gunlink _wunlink
#define grename _wrename
#define gtmpnam _wtmpnam
#define gtempnam _wtempnam
#define gfindfirst _wfindfirst
#define gfinddata_t _wfinddata_t
#define gfindnext _wfindnext
#define gfindclose _findclose
#define gstat _wstat
#define gaccess _waccess
typedef struct _stat gstat_t;
#define gmkdir _wmkdir
#define gchdir _wchdir
#define grmdir _wrmdir
#define gremove _wremove
#define ggetcwd _wgetcwd
#define gtolower towlower
#define gtoupper towupper
#define gisspace iswspace
#define gisdigit iswdigit
#define gisxdigit iswxdigit
#define gisalnum iswalnum
#define gisalpha iswalpha
#define gisupper iswupper
#define gislower iswlower
#define gatoi(s) wcstol(s, NULL, 10)
#define gctime _wctime
#define ggetenv _wgetenv
#define gexecvp _wexecvp
#else /* ! UNICODE */
#define T(s) s
#define TSZ(x) (sizeof(x))
#define TASTRL(x) (strlen(x) + 1)
typedef char char_t;
#if WIN
typedef unsigned char uchar_t;
#endif
#define gsprintf sprintf
#define gprintf printf
#define gfprintf fprintf
#define gsscanf sscanf
#define gvsprintf vsprintf
#define gstrcpy strcpy
#define gstrncpy strncpy
#define gstrncat strncat
#define gstrlen strlen
#define gstrcat strcat
#define gstrcmp strcmp
#define gstrncmp strncmp
#define gstricmp stricmp
#define gstrchr strchr
#define gstrrchr strrchr
#define gstrtok strtok
#define gstrnset strnset
#define gstrstr strstr
#define gfopen fopen
#define gopen open
#define gcreat creat
#define gfgets fgets
#define gfputs fputs
#define gunlink unlink
#define grename rename
#define gtmpnam tmpnam
#define gtempnam tempnam
#define gfindfirst _findfirst
#define gfinddata_t _finddata_t
#define gfindnext _findnext
#define gfindclose _findclose
#define gstat stat
#define gaccess access
typedef struct stat gstat_t;
#define gmkdir mkdir
#define gchdir chdir
#define grmdir rmdir
#define gremove remove
#define ggetcwd getcwd
#define gtolower tolower
#define gtoupper toupper
#define gisspace isspace
#define gisdigit isdigit
#define gisxdigit isxdigit
#define gisalnum isalnum
#define gisalpha isalpha
#define gisupper isupper
#define gislower islower
#define gatoi atoi
#define gctime ctime
#define ggetenv getenv
#define gexecvp execvp
#ifndef VXW486
#define gmain main
#endif
#endif
/********************************** Defines ***********************************/
#define FNAMESIZE 256 /* Max length of file names */
#define E_MAX_ERROR 4096
/*
* Error types
*/
#define E_ASSERT 0x1 /* Assertion error */
#define E_LOG 0x2 /* Log error to log file */
#define E_USER 0x3 /* Error that must be displayed */
#define E_L T(__FILE__), __LINE__
#define E_ARGS_DEC char_t *file, int line
#define E_ARGS file, line
#if ASSERT
#define a_assert(C) if (C) ; else error(E_L, E_ASSERT, T("%s"), #C)
#else
#define a_assert(C) if (1) ; else
#endif
#define VALUE_VALID { {0}, integer, 1 }
#define VALUE_INVALID { {0}, undefined, 0 }
/*
* Allocation flags
*/
#define VALUE_ALLOCATE 0x1
#define value_numeric(t) (t == integer)
#define value_str(t) (t >= string || t <= bytes)
#define value_ok(t) (t > undefined && t <= symbol)
/*
* These values are not prefixed so as to aid code readability
*/
#ifndef UW
#pragma pack(2)
#endif
typedef enum {
undefined = 0,
integer = 1,
string = 2,
bytes = 3,
errmsg = 4
} value_type_t;
/*
* In UW, bit fields default to unsigned unless explicitly defined as signed.
* Unfortunately, enum become ints, but not explicitly signed. Thus, if using
* an enum type in a bit field, it becomes unsigned, but we need signed. So
* for UW we declare value_type_t to be a signed int to make this all work.
*/
typedef struct {
union {
long integer;
char_t *string;
char_t *bytes;
char_t *errmsg;
void *symbol;
} value;
#if UW
signed int type : 8;
#else
value_type_t type : 8;
#endif
unsigned int valid : 1;
unsigned int user_def_1 : 1;
unsigned int allocated : 1; /* String was balloced */
} value_t;
/*
* Extract a string from the value depending whether inline or via pointer
*/
#define value_strget(v) \
(((v)->type == bytes) ? (v)->value.bytes : (v)->value.string)
#ifndef UW
#pragma pack()
#endif
/******************************************************************************/
/*
* A ring queue allows maximum utilization of memory for data storage and is
* ideal for input/output buffering. This module provides a highly effecient
* 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 fillers responsibility to ensure
* the ringq is never filled such that servp == endp.
*
* It is the fillers 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.
*/
/*
* Ring queue buffer structure
*/
typedef struct {
unsigned char *buf; /* Holding buffer for data */
unsigned char *servp; /* Pointer to start of data */
unsigned char *endp; /* Pointer to end of data */
unsigned char *endbuf; /* Pointer to end of buffer */
int buflen; /* Length of ring queue */
int maxsize; /* Maximum size */
int increment; /* Growth increment */
} ringq_t;
/*
* Block allocation definitions
*/
#define B_L __FILE__, __LINE__
#define B_ARGS_DEC char *file, int line
#define B_ARGS file, line
/*
* Block classes are: 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192,
* 16384, 32768, 65536
*/
#define B_SHIFT 4 /* Convert size to class */
#define B_ROUND ((1 << (B_SHIFT)) - 1)
#define B_MAX_CLASS 13 /* Maximum class number + 1 */
#define B_MALLOCED 0x80000000 /* Block was malloced */
#define B_DEFAULT_MEM (64 * 1024) /* Default memory allocation */
#define B_MAX_FILES (512) /* Maximum number of files */
#define B_FILL_CHAR (0x77) /* Fill byte for buffers */
#define B_FILL_WORD (0x77777777) /* Fill word for buffers */
#define B_MAX_BLOCKS (64 * 1024) /* Maximum allocated blocks */
/*
* Flags. The integer value is used as an arbitrary value to fill the flags.
*/
#define B_USE_MALLOC 0x1 /* Okay to use malloc if required */
#define B_USER_BUF 0x2 /* User supplied buffer for mem */
#define B_INTEGRITY 0x8124000 /* Integrity value */
#define B_INTEGRITY_MASK 0xFFFF000 /* Integrity mask */
/*
* The symbol table record for each symbol entry
*/
typedef struct sym_t {
struct sym_t *forw; /* Pointer to next hash list */
value_t name; /* Name of symbol */
value_t content; /* Value of symbol */
int arg; /* Parameter value */
} sym_t;
typedef int sym_fd_t; /* Returned by symOpen */
/*
* Socket flags
*/
#define SOCKET_EOF 0x1 /* Seen end of file */
#define SOCKET_CONNECTING 0x2 /* Connect in progress */
#define SOCKET_BROADCAST 0x4 /* Broadcast mode */
#define SOCKET_PENDING 0x8 /* Message pending on this socket */
#define SOCKET_FLUSHING 0x10 /* Background flushing */
#define SOCKET_LISTENING 0x20 /* Server socket listening */
/*
* Socket error values
*/
#define SOCKET_WOULDBLOCK 1 /* Socket would block on I/O */
#define SOCKET_RESET 2 /* Socket has been reset */
#define SOCKET_NETDOWN 3 /* Network is down */
#define SOCKET_AGAIN 4 /* Issue the request again */
#define SOCKET_INTR 5 /* Call was interrupted */
#define SOCKET_INVAL 6 /* Invalid */
/*
* Handler event masks
*/
#define SOCKET_READABLE 0x2 /* Make socket readable */
#define SOCKET_WRITABLE 0x4 /* Make socket writable */
#define SOCKET_EXCEPTION 0x8 /* Interested in exceptions */
#define SOCKET_BUFSIZ 512 /* Underlying buffer size */
typedef void (*socketHandler_t)(int sid, int mask, int data);
typedef int (*socketAccept_t)(int sid, char *ipaddr, int port);
/*
* Script engines
*/
#define EMF_SCRIPT_JSCRIPT 0 /* javascript */
#define EMF_SCRIPT_TCL 1 /* tcl */
#define EMF_SCRIPT_EJSCRIPT 2 /* Ejscript */
#define EMF_SCRIPT_MAX 3
#define MAXINT INT_MAX
#define BITSPERBYTE 8
#define BITS(type) (BITSPERBYTE * (int) sizeof(type))
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
/******************************* Per O/S Defines ******************************/
#if VXW486 || LINUX || LYNX
#ifndef O_BINARY
#define O_BINARY 0
#endif
#define SOCKET_ERROR -1
#endif
#if WIN
#undef R_OK
#define R_OK 4
#undef W_OK
#define W_OK 2
#undef X_OK
#define X_OK 1
#undef F_OK
#define F_OK 0
#endif
/********************************* Prototypes *********************************/
extern void bclose();
extern int bopen(void *buf, int bufsize, int flags);
#if NO_BALLOC
#undef B_L
#define B_L x
#define balloc(x, num) malloc(num)
#define bfree(x, p) free(p)
#define bfreeSafe(x, p) \
if (p) { bfree(x, p); } else
#define brealloc(x, p, num) realloc(p, num)
extern char *bstrdupANoBalloc(char *s);
#define bstrdupA(x, s) bstrdupANoBalloc(s)
#if UNICODE
extern char_t *bstrdupNoBalloc(char_t *s);
#define bstrdup(x, s) bstrdupNoBalloc(s)
#define gstrdup(x, s) bstrdupNoBalloc(s)
#else /* Not UNICODE */
#define bstrdup(x, s) bstrdupANoBalloc(s)
#define gstrdup(x, s) bstrdupANoBalloc(s)
#endif /* UNICODE */
#else /* BALLOC */
extern void *balloc(B_ARGS_DEC, int size);
extern void bfree(B_ARGS_DEC, void *mp);
extern void *brealloc(B_ARGS_DEC, void *buf, int newsize);
extern void bstats(int handle, void (*writefn)(int fd, char_t *fmt, ...));
extern char_t *bstrdup(B_ARGS_DEC, char_t *s);
extern void bfreeSafe(B_ARGS_DEC, void* mp);
#define gstrdup(B_ARGS, s) bstrdup(B_ARGS, s)
#if UNICODE
extern char *bstrdupA(B_ARGS_DEC, char *s);
#else
#define bstrdupA bstrdup
#endif /* UNICODE */
#endif /* BALLOC */
#if !LINUX
extern char_t* basename(char_t* name);
#endif
extern void *emfCreateTimer(int delay, void (*routine)(long arg), long arg);
extern void emfDeleteTimer(void *id);
extern int emfInstGet();
extern void emfInstSet(int inst);
extern void error(E_ARGS_DEC, int flags, char_t *fmt, ...);
extern int hAlloc(void*** map);
extern int hFree(void*** map, int handle);
extern int hAllocEntry(void ***list, int *max, int size);
extern int ringqOpen(ringq_t *rq, int increment, int maxsize);
extern void ringqClose(ringq_t *rq);
extern int ringqLen(ringq_t *rq);
extern int ringqPutc(ringq_t *rq, char_t c);
extern int ringqInsertc(ringq_t *rq, char_t c);
extern int ringqPutstr(ringq_t *rq, char_t *str);
extern int ringqGetc(ringq_t *rq);
extern int gvsnprintf(char_t **s, int n, char_t *fmt, va_list arg);
extern int gsnprintf(char_t **s, int n, char_t *fmt, ...);
#if UNICODE
extern int ringqPutcA(ringq_t* rq, char c);
extern int ringqInsertcA(ringq_t* rq, char c);
extern int ringqPutstrA(ringq_t* rq, char* str);
extern int ringqGetcA(ringq_t* rq);
#else
#define ringqPutcA ringqPutc
#define ringqInsertcA ringqInsertc
#define ringqPutstrA ringqPutstr
#define ringqGetcA ringqGetc
#endif
extern int ringqPutBlk(ringq_t *rq, unsigned char *buf, int len);
extern int ringqPutBlkMax(ringq_t *rq);
extern void ringqPutBlkAdj(ringq_t *rq, int size);
extern int ringqGetBlk(ringq_t *rq, unsigned char *buf, int len);
extern int ringqGetBlkMax(ringq_t *rq);
extern void ringqGetBlkAdj(ringq_t *rq, int size);
extern void ringqFlush(ringq_t *rq);
extern int scriptSetVar(int engine, char_t *var, char_t *value);
extern int scriptEval(int engine, char_t *cmd, char_t **rslt, int chan);
extern void socketClose();
extern void socketCloseConnection(int sid);
extern void socketCreateHandler(int sid, int mask, socketHandler_t
handler, int arg);
extern void socketDeleteHandler(int sid);
extern int socketEof(int sid);
extern int socketFlush(int sid, int block);
extern int socketGets(int sid, char_t** buf);
extern int socketInputBuffered(int sid);
extern int socketOpen();
extern int socketOpenConnection(char *host, int port,
socketAccept_t accept, int flags);
extern void socketProcess();
extern int socketRead(int sid, char *buf, int len);
extern int socketReady();
extern int socketWrite(int sid, char *buf, int len);
extern int socketWriteString(int sid, char_t *buf);
extern int socketSelect();
extern char_t *strlower(char_t *string);
extern char_t *strupper(char_t *string);
extern char_t *stritoa(int n, char_t *string, int width);
extern sym_fd_t symOpen(int hash_size);
extern void symClose(sym_fd_t sd, void (*cleanup)(sym_t *sp));
extern sym_t *symLookup(sym_fd_t sd, char_t *name);
extern sym_t *symEnter(sym_fd_t sd, char_t *name, value_t v, int arg);
extern int symDelete(sym_fd_t sd, char_t *name);
extern void symWalk(sym_fd_t sd, void (*fn)(sym_t *symp));
extern void trace(int lev, char_t *fmt, ...);
extern value_t valueInteger(long value);
extern value_t valueString(char_t *value, int flags);
extern value_t valueErrmsg(char_t *value);
extern void valueFree(value_t *v);
extern char_t *ascToUni(char_t *ubuf, char *str, int nBytes);
extern char *uniToAsc(char *buf, char_t *ustr, int nBytes);
extern char_t *ballocAscToUni(char * cp);
extern char *ballocUniToAsc(char_t * unip, int ulen);
#endif /* _h_UEMF */
/******************************************************************************/

203
cpukit/httpd/url.c Normal file
View File

@@ -0,0 +1,203 @@
/*
* url.c -- Parse URLs
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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 a 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 tag and the query
*/
if ((cp = gstrchr(tok, '#')) != NULL) {
*cp++ = '\0';
path = tok;
tok = cp;
}
if ((cp = gstrchr(tok, '?')) != NULL) {
*cp++ = '\0';
query = cp;
}
/*
* 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;
}
/******************************************************************************/

74
cpukit/httpd/value.c Normal file
View File

@@ -0,0 +1,74 @@
/*
* value.c -- Generic type (holds all types)
*
* Copyright (c) Go Ahead Software, Inc., 1995-1999
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** Description *********************************/
/*
* This module provides a generic type that can hold all possible types.
* It is designed to provide maximum effeciency.
*/
/********************************* Includes ***********************************/
#include "uemf.h"
/*********************************** Locals ***********************************/
/*********************************** Code *************************************/
/*
* Initialize a integer value.
*/
value_t valueInteger(long value)
{
value_t v = VALUE_VALID;
v.value.integer = value;
return v;
}
/******************************************************************************/
/*
* Initialize a string value. Note: not allocation
*/
value_t valueString(char_t *value, int flags)
{
value_t v = VALUE_VALID;
v.type = string;
if (flags & VALUE_ALLOCATE) {
v.allocated = 1;
v.value.string = gstrdup(B_L, value);
} else {
v.allocated = 0;
v.value.string = value;
}
return v;
}
/******************************************************************************/
/*
* Free any storage allocated for a value.
*/
void valueFree(value_t *v)
{
a_assert(v);
if (v->valid && v->allocated && v->type == string &&
v->value.string != NULL) {
bfree(B_L, v->value.string);
}
v->type = undefined;
v->valid = 0;
v->allocated = 0;
}
/******************************************************************************/

149
cpukit/httpd/wbase64.c Normal file
View File

@@ -0,0 +1,149 @@
/*
* base64.c -- Base64 Mime encoding
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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;
char_t* 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;
char_t* 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';
}
}
/******************************************************************************/

177
cpukit/httpd/webcomp.c Normal file
View File

@@ -0,0 +1,177 @@
/*
* webcomp -- Compile web pages into C source
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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;
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",
ctime(&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 (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';
}
/*
* 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;
}
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;
}
/******************************************************************************/

410
cpukit/httpd/webmain.c Normal file
View File

@@ -0,0 +1,410 @@
/*
* main.c -- Main program for the GoAhead WebServer (LINUX version)
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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>
/*********************************** Locals ***********************************/
/*
* Change configuration here
*/
static char_t *rootWeb = T("web"); /* 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 LINUX
*/
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");
}
/*
* 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() || socketSelect()) {
socketProcess();
}
}
/*
* Close the socket module, report memory leaks and close the memory allocator
*/
websCloseServer();
socketClose();
#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], dir[128], webdir[128];
char *cp;
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);
/*
* Set ../web as the root web. Modify this to suit your needs
*/
getcwd(dir, sizeof(dir));
if ((cp = strrchr(dir, '/'))) {
*cp = '\0';
}
sprintf(webdir, "%s/%s", dir, rootWeb);
/*
* 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
*/
websSetDefaultPage(T("default.asp"));
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)
{
struct sigaction act;
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) {
websRedirect(wp, T("home.asp"));
return 1;
}
return 0;
}
/******************************************************************************/
#if B_STATS
static void memLeaks()
{
int fd;
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
/******************************************************************************/

138
cpukit/httpd/webpage.c Normal file
View File

@@ -0,0 +1,138 @@
/*
* Page.c -- Support for page retrieval.
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/******************************** 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));
#if 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)
{
#if 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)
{
#if 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)
{
#if 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)
{
#if 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));
#if WEBS_PAGE_ROM
websRomPageSeek(wp, offset, SEEK_CUR);
#else
lseek(wp->docfd, offset, SEEK_CUR);
#endif
}
/******************************************************************************/

12
cpukit/httpd/webrom.c Normal file
View File

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

1841
cpukit/httpd/webs.c Normal file

File diff suppressed because it is too large Load Diff

182
cpukit/httpd/webs.h Normal file
View File

@@ -0,0 +1,182 @@
/*
* webs.h -- Go Ahead Web public header
*
* Copyright (c) Go Ahead Software Inc., 1992-1999. All Rights Reserved.
*
* See the file "license.txt" for information on usage and redistribution
*/
#ifndef _h_WEBS
#define _h_WEBS 1
/******************************** Description *********************************/
/*
* Go Ahead 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"
/********************************** Defines ***********************************/
#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 */
/*
* 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_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 */
void* 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* password; /* Authorization password */
char_t* userName; /* Authorization username */
char_t* cookie; /* Cookie string */
char_t* userAgent; /* User agent (browser) */
int sid; /* Socket id (handler) */
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 */
int docfd; /* Document file descriptor */
int numbytes; /* Bytes to transfer to browser */
int written; /* Bytes actually transferred */
void (*writeSocket)(struct websRec *wp);
} websRec;
typedef websRec *webs_t;
typedef websRec websType;
/******************************** Prototypes **********************************/
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, ...);
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 *websGetPassword();
extern int websGetPort();
extern char_t *websGetPublishDir(char_t *path, char_t **urlPrefix);
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 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 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 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 websWriteBlockData(webs_t wp, char *buf, int nChars);
extern int websValid(webs_t wp);
extern int websValidateUrl(webs_t wp, char_t *path);
extern int websCloseFileHandle(webs_t wp);
/*
* Prototypes for functions available when running as part of the
* GoAhead Embedded Management Framework (EMF)
*/
#if EMF
extern void websFormExplain(webs_t wp, char_t *path, char_t *query);
#endif
#endif /* _h_WEBS */
/******************************************************************************/

39
cpukit/httpd/websuemf.c Normal file
View File

@@ -0,0 +1,39 @@
/*
* websuemf.c -- GoAhead Micro Embedded Management Framework
*
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*/
/********************************** Description *******************************/
/*
* This modules provides compatibility with the full GoAhead EMF.
*/
/*********************************** Includes *********************************/
#include "wsIntrn.h"
/************************************* 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;
if (ejEval(ejid, cmd, NULL) ) {
return 0;
} else {
return -1;
}
}
return -1;
}
/******************************************************************************/

268
cpukit/httpd/wsIntrn.h Normal file
View File

@@ -0,0 +1,268 @@
/*
* wsIntrn.h -- Internal Go Ahead Web server header
*
* Copyright (c) Go Ahead Software Inc., 1992-1999. All Rights Reserved.
*
* See the file "license.txt" for information on usage and redistribution
*/
#ifndef _h_WEBS_INTERNAL
#define _h_WEBS_INTERNAL 1
/******************************** Description *********************************/
/*
* Internal Go Ahead Web Server header. This defines the Web private APIs
* Include this header when you want to create URL handlers.
*/
/*********************************** Defines **********************************/
/*
* Define this to enable login 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
* Note: this is not yet fully implemented.
* #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>
#if WIN
#include <fcntl.h>
#include <sys/stat.h>
#include <io.h>
#endif
#if CE
#if ! UEMF
#include <io.h>
#endif
#endif
#if NW
#include <fcntl.h>
#include <sys/stat.h>
#endif
#if LYNX
#include <fcntl.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#endif
#if UNIX
#include <fcntl.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#endif
#if QNX4
#include <fcntl.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#include <unix.h>
#endif
#if UW
#include <fcntl.h>
#include <sys/stat.h>
#endif
#if VXW486
#include <vxWorks.h>
#include <fcntl.h>
#include <sys/stat.h>
#endif
#if UEMF
#include "uemf.h"
#include "ej.h"
#else
#include "emf/emfInternal.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 */
/*
* 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 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 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 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);
/*
* Prototypes for functions available when running as part of the
* GoAhead Embedded Management Framework (EMF)
*/
#if EMF
extern int websEmfOpen();
extern void websEmfClose();
extern void websSetEmfEnvironment(webs_t wp);
#endif
#endif /* _h_WEBS_INTERNAL */
/******************************************************************************/

View File

@@ -5,7 +5,8 @@
AUTOMAKE_OPTIONS = foreign 1.4
ACLOCAL_AMFLAGS = -I $(RTEMS_TOPdir)/aclocal
SUBDIRS = include kern lib libc net netinet nfs rtems rtems_servers wrapup
SUBDIRS = include kern lib libc net netinet nfs rtems rtems_servers \
rtems_webserver wrapup
EXTRA_DIST = \
CHANGELOG \