forked from Imagelibrary/rtems
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:
@@ -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 \
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -42,5 +42,6 @@ netinet/Makefile
|
||||
nfs/Makefile
|
||||
rtems/Makefile
|
||||
rtems_servers/Makefile
|
||||
rtems_webserver/Makefile
|
||||
wrapup/Makefile
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
59
c/src/libnetworking/rtems_webserver/Makefile.in
Normal file
59
c/src/libnetworking/rtems_webserver/Makefile.in
Normal 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
c/src/libnetworking/rtems_webserver/asp.c
Normal file
313
c/src/libnetworking/rtems_webserver/asp.c
Normal 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
c/src/libnetworking/rtems_webserver/balloc.c
Normal file
836
c/src/libnetworking/rtems_webserver/balloc.c
Normal 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
c/src/libnetworking/rtems_webserver/default.c
Normal file
389
c/src/libnetworking/rtems_webserver/default.c
Normal 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
c/src/libnetworking/rtems_webserver/ej.h
Normal file
226
c/src/libnetworking/rtems_webserver/ej.h
Normal 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
c/src/libnetworking/rtems_webserver/ejlex.c
Normal file
679
c/src/libnetworking/rtems_webserver/ejlex.c
Normal 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
c/src/libnetworking/rtems_webserver/ejparse.c
Normal file
1665
c/src/libnetworking/rtems_webserver/ejparse.c
Normal file
File diff suppressed because it is too large
Load Diff
163
c/src/libnetworking/rtems_webserver/form.c
Normal file
163
c/src/libnetworking/rtems_webserver/form.c
Normal 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
c/src/libnetworking/rtems_webserver/h.c
Normal file
171
c/src/libnetworking/rtems_webserver/h.c
Normal 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
c/src/libnetworking/rtems_webserver/handler.c
Normal file
284
c/src/libnetworking/rtems_webserver/handler.c
Normal 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
c/src/libnetworking/rtems_webserver/mime.c
Normal file
112
c/src/libnetworking/rtems_webserver/mime.c
Normal 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
c/src/libnetworking/rtems_webserver/misc.c
Normal file
581
c/src/libnetworking/rtems_webserver/misc.c
Normal 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
c/src/libnetworking/rtems_webserver/ringq.c
Normal file
537
c/src/libnetworking/rtems_webserver/ringq.c
Normal 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
c/src/libnetworking/rtems_webserver/rom.c
Normal file
198
c/src/libnetworking/rtems_webserver/rom.c
Normal 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
|
||||
|
||||
/******************************************************************************/
|
||||
7
c/src/libnetworking/rtems_webserver/rtems_webserver.h
Normal file
7
c/src/libnetworking/rtems_webserver/rtems_webserver.h
Normal file
@@ -0,0 +1,7 @@
|
||||
/*
|
||||
* rtems_webserver.h --
|
||||
*
|
||||
*/
|
||||
|
||||
int rtems_initialize_webserver();
|
||||
|
||||
109
c/src/libnetworking/rtems_webserver/security.c
Normal file
109
c/src/libnetworking/rtems_webserver/security.c
Normal 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
c/src/libnetworking/rtems_webserver/socket.c
Normal file
991
c/src/libnetworking/rtems_webserver/socket.c
Normal 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
c/src/libnetworking/rtems_webserver/sym.c
Normal file
452
c/src/libnetworking/rtems_webserver/sym.c
Normal 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
c/src/libnetworking/rtems_webserver/uemf.c
Normal file
193
c/src/libnetworking/rtems_webserver/uemf.c
Normal 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
c/src/libnetworking/rtems_webserver/uemf.h
Normal file
666
c/src/libnetworking/rtems_webserver/uemf.h
Normal 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
c/src/libnetworking/rtems_webserver/url.c
Normal file
203
c/src/libnetworking/rtems_webserver/url.c
Normal 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
c/src/libnetworking/rtems_webserver/value.c
Normal file
74
c/src/libnetworking/rtems_webserver/value.c
Normal 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
c/src/libnetworking/rtems_webserver/wbase64.c
Normal file
149
c/src/libnetworking/rtems_webserver/wbase64.c
Normal 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
c/src/libnetworking/rtems_webserver/webcomp.c
Normal file
177
c/src/libnetworking/rtems_webserver/webcomp.c
Normal 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
c/src/libnetworking/rtems_webserver/webmain.c
Normal file
410
c/src/libnetworking/rtems_webserver/webmain.c
Normal 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
c/src/libnetworking/rtems_webserver/webpage.c
Normal file
138
c/src/libnetworking/rtems_webserver/webpage.c
Normal 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
c/src/libnetworking/rtems_webserver/webrom.c
Normal file
12
c/src/libnetworking/rtems_webserver/webrom.c
Normal 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
c/src/libnetworking/rtems_webserver/webs.c
Normal file
1841
c/src/libnetworking/rtems_webserver/webs.c
Normal file
File diff suppressed because it is too large
Load Diff
182
c/src/libnetworking/rtems_webserver/webs.h
Normal file
182
c/src/libnetworking/rtems_webserver/webs.h
Normal 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
c/src/libnetworking/rtems_webserver/websuemf.c
Normal file
39
c/src/libnetworking/rtems_webserver/websuemf.c
Normal 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
c/src/libnetworking/rtems_webserver/wsIntrn.h
Normal file
268
c/src/libnetworking/rtems_webserver/wsIntrn.h
Normal 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 */
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -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
59
cpukit/httpd/Makefile.in
Normal 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
313
cpukit/httpd/asp.c
Normal 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
836
cpukit/httpd/balloc.c
Normal 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
389
cpukit/httpd/default.c
Normal 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
226
cpukit/httpd/ej.h
Normal 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
679
cpukit/httpd/ejlex.c
Normal 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
1665
cpukit/httpd/ejparse.c
Normal file
File diff suppressed because it is too large
Load Diff
163
cpukit/httpd/form.c
Normal file
163
cpukit/httpd/form.c
Normal 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
171
cpukit/httpd/h.c
Normal 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
284
cpukit/httpd/handler.c
Normal 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
112
cpukit/httpd/mime.c
Normal 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
581
cpukit/httpd/misc.c
Normal 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
537
cpukit/httpd/ringq.c
Normal 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
198
cpukit/httpd/rom.c
Normal 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
|
||||
|
||||
/******************************************************************************/
|
||||
7
cpukit/httpd/rtems_webserver.h
Normal file
7
cpukit/httpd/rtems_webserver.h
Normal file
@@ -0,0 +1,7 @@
|
||||
/*
|
||||
* rtems_webserver.h --
|
||||
*
|
||||
*/
|
||||
|
||||
int rtems_initialize_webserver();
|
||||
|
||||
109
cpukit/httpd/security.c
Normal file
109
cpukit/httpd/security.c
Normal 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
991
cpukit/httpd/socket.c
Normal 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
452
cpukit/httpd/sym.c
Normal 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
193
cpukit/httpd/uemf.c
Normal 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
666
cpukit/httpd/uemf.h
Normal 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
203
cpukit/httpd/url.c
Normal 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
74
cpukit/httpd/value.c
Normal 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
149
cpukit/httpd/wbase64.c
Normal 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
177
cpukit/httpd/webcomp.c
Normal 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
410
cpukit/httpd/webmain.c
Normal 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
138
cpukit/httpd/webpage.c
Normal 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
12
cpukit/httpd/webrom.c
Normal 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
1841
cpukit/httpd/webs.c
Normal file
File diff suppressed because it is too large
Load Diff
182
cpukit/httpd/webs.h
Normal file
182
cpukit/httpd/webs.h
Normal 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
39
cpukit/httpd/websuemf.c
Normal 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
268
cpukit/httpd/wsIntrn.h
Normal 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 */
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -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 \
|
||||
|
||||
Reference in New Issue
Block a user