mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-05 15:15:44 +00:00
Remove (Moved to cpukit/http).
This commit is contained in:
@@ -1,2 +0,0 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
@@ -1,97 +0,0 @@
|
||||
##
|
||||
## $Id$
|
||||
##
|
||||
|
||||
include $(top_srcdir)/automake/compile.am
|
||||
|
||||
EXTRA_LIBRARIES =
|
||||
CLEANFILES =
|
||||
|
||||
AM_CPPFLAGS += -DWEBS -DUEMF -DOS="RTEMS"
|
||||
|
||||
if HAS_NETWORKING
|
||||
if HAS_POSIX
|
||||
include_goaheaddir = $(includedir)/goahead
|
||||
|
||||
include_HEADERS = rtems_webserver.h
|
||||
include_goahead_HEADERS = ej.h ejIntrn.h emfdb.h md5.h uemf.h um.h webs.h \
|
||||
wsIntrn.h
|
||||
|
||||
EXTRA_LIBRARIES += libhttpd.a
|
||||
CLEANFILES += libhttpd.a
|
||||
libhttpd_a_SOURCES = asp.c balloc.c default.c ejlex.c ejparse.c emfdb.c \
|
||||
form.c h.c handler.c md5c.c mime.c misc.c webpage.c ringq.c rom.c \
|
||||
security.c sock.c socket.c sym.c uemf.c um.c url.c value.c wbase64.c \
|
||||
webrom.c webs.c websuemf.c webmain.c
|
||||
libhttpd_a_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAGS_OPTIMIZE_V)
|
||||
|
||||
EXTRA_LIBRARIES += libhttpd_g.a
|
||||
CLEANFILES += libhttpd_g.a
|
||||
libhttpd_g_a_SOURCES = $(libhttpd_a_SOURCES)
|
||||
libhttpd_g_a_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAGS_DEBUG_V)
|
||||
|
||||
noinst_DATA = libhttpd$(LIB_VARIANT).a
|
||||
endif
|
||||
endif
|
||||
|
||||
all-local: $(PREINSTALL_FILES)
|
||||
|
||||
EXTRA_DIST = webcomp.c webpage.c
|
||||
|
||||
PREINSTALL_DIRS =
|
||||
PREINSTALL_FILES =
|
||||
|
||||
$(PROJECT_INCLUDE)/$(dirstamp):
|
||||
@$(mkdir_p) $(PROJECT_INCLUDE)
|
||||
@: > $(PROJECT_INCLUDE)/$(dirstamp)
|
||||
PREINSTALL_DIRS += $(PROJECT_INCLUDE)/$(dirstamp)
|
||||
|
||||
if HAS_NETWORKING
|
||||
if HAS_POSIX
|
||||
$(PROJECT_INCLUDE)/goahead/$(dirstamp):
|
||||
@$(mkdir_p) $(PROJECT_INCLUDE)/goahead
|
||||
@: > $(PROJECT_INCLUDE)/goahead/$(dirstamp)
|
||||
PREINSTALL_DIRS += $(PROJECT_INCLUDE)/goahead/$(dirstamp)
|
||||
|
||||
$(PROJECT_INCLUDE)/rtems_webserver.h: rtems_webserver.h $(PROJECT_INCLUDE)/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems_webserver.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems_webserver.h
|
||||
|
||||
$(PROJECT_INCLUDE)/goahead/ej.h: ej.h $(PROJECT_INCLUDE)/goahead/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/goahead/ej.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/goahead/ej.h
|
||||
|
||||
$(PROJECT_INCLUDE)/goahead/ejIntrn.h: ejIntrn.h $(PROJECT_INCLUDE)/goahead/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/goahead/ejIntrn.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/goahead/ejIntrn.h
|
||||
|
||||
$(PROJECT_INCLUDE)/goahead/emfdb.h: emfdb.h $(PROJECT_INCLUDE)/goahead/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/goahead/emfdb.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/goahead/emfdb.h
|
||||
|
||||
$(PROJECT_INCLUDE)/goahead/md5.h: md5.h $(PROJECT_INCLUDE)/goahead/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/goahead/md5.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/goahead/md5.h
|
||||
|
||||
$(PROJECT_INCLUDE)/goahead/uemf.h: uemf.h $(PROJECT_INCLUDE)/goahead/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/goahead/uemf.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/goahead/uemf.h
|
||||
|
||||
$(PROJECT_INCLUDE)/goahead/um.h: um.h $(PROJECT_INCLUDE)/goahead/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/goahead/um.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/goahead/um.h
|
||||
|
||||
$(PROJECT_INCLUDE)/goahead/webs.h: webs.h $(PROJECT_INCLUDE)/goahead/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/goahead/webs.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/goahead/webs.h
|
||||
|
||||
$(PROJECT_INCLUDE)/goahead/wsIntrn.h: wsIntrn.h $(PROJECT_INCLUDE)/goahead/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/goahead/wsIntrn.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/goahead/wsIntrn.h
|
||||
endif
|
||||
endif
|
||||
|
||||
CLEANFILES += $(PREINSTALL_FILES)
|
||||
DISTCLEANFILES = $(PREINSTALL_DIRS)
|
||||
|
||||
include $(top_srcdir)/automake/local.am
|
||||
@@ -1,36 +0,0 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
Notes on merging GoAhead Webs 2.1.4. Eventually RTEMS should be supported
|
||||
in their distributions and this directory removed.
|
||||
|
||||
Applied patch from Antti P Miettinen <antti.p.miettinen@nokia.com>.
|
||||
|
||||
Obtain the original distribution from http://www.goahead.com for
|
||||
documentation.
|
||||
|
||||
Porting
|
||||
=======
|
||||
- added rtems complier flags to uemf.h and misc.c
|
||||
- following source files are distributed with the web server
|
||||
but not currently used by RTEMS
|
||||
[cgi.c, sockGen.c, umui.c, websSSL.c, websda.c]
|
||||
|
||||
Tailoring
|
||||
=========
|
||||
socket.c is RTEMS specific
|
||||
|
||||
Renames
|
||||
=======
|
||||
|
||||
Distributed as This Directory
|
||||
============== ================
|
||||
base64.c wbase64.c
|
||||
page.c webpage.c
|
||||
|
||||
RTEMS Specific Additions
|
||||
========================
|
||||
webmain.c
|
||||
rtems_webserver.h
|
||||
|
||||
@@ -1,321 +0,0 @@
|
||||
/*
|
||||
* asp.c -- Active Server Page Support
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* The ASP module processes ASP pages and executes embedded scripts. It
|
||||
* support an open scripting architecture with in-built support for
|
||||
* Ejscript(TM).
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#include "wsIntrn.h"
|
||||
|
||||
/********************************** Locals ************************************/
|
||||
|
||||
static sym_fd_t websAspFunctions = -1; /* Symbol table of functions */
|
||||
static int aspOpenCount = 0; /* count of apps using this module */
|
||||
|
||||
/***************************** Forward Declarations ***************************/
|
||||
|
||||
static char_t *strtokcmp(char_t *s1, char_t *s2);
|
||||
static char_t *skipWhite(char_t *s);
|
||||
|
||||
/************************************* Code ***********************************/
|
||||
/*
|
||||
* Create script spaces and commands
|
||||
*/
|
||||
|
||||
int websAspOpen()
|
||||
{
|
||||
if (++aspOpenCount == 1) {
|
||||
/*
|
||||
* Create the table for ASP functions
|
||||
*/
|
||||
websAspFunctions = symOpen(WEBS_SYM_INIT * 2);
|
||||
|
||||
/*
|
||||
* Create standard ASP commands
|
||||
*/
|
||||
websAspDefine(T("write"), websAspWrite);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************************* Code ***********************************/
|
||||
/*
|
||||
* Close Asp symbol table.
|
||||
*/
|
||||
|
||||
void websAspClose()
|
||||
{
|
||||
if (--aspOpenCount <= 0) {
|
||||
if (websAspFunctions != -1) {
|
||||
symClose(websAspFunctions);
|
||||
websAspFunctions = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Process ASP requests and expand all scripting commands. We read the
|
||||
* entire ASP page into memory and then process. If you have really big
|
||||
* documents, it is better to make them plain HTML files rather than ASPs.
|
||||
*/
|
||||
|
||||
int websAspRequest(webs_t wp, char_t *lpath)
|
||||
{
|
||||
websStatType sbuf;
|
||||
char *rbuf;
|
||||
char_t *token, *lang, *result, *path, *ep, *cp, *buf, *nextp;
|
||||
char_t *last;
|
||||
int rc, engine, len, ejid;
|
||||
|
||||
a_assert(websValid(wp));
|
||||
a_assert(lpath && *lpath);
|
||||
|
||||
rc = -1;
|
||||
buf = NULL;
|
||||
rbuf = NULL;
|
||||
engine = EMF_SCRIPT_EJSCRIPT;
|
||||
wp->flags |= WEBS_HEADER_DONE;
|
||||
path = websGetRequestPath(wp);
|
||||
|
||||
/*
|
||||
* Create Ejscript instance in case it is needed
|
||||
*/
|
||||
ejid = ejOpenEngine(wp->cgiVars, websAspFunctions);
|
||||
if (ejid < 0) {
|
||||
websError(wp, 200, T("Can't create Ejscript engine"));
|
||||
goto done;
|
||||
}
|
||||
ejSetUserHandle(ejid, (int) wp);
|
||||
|
||||
if (websPageStat(wp, lpath, path, &sbuf) < 0) {
|
||||
websError(wp, 200, T("Can't stat %s"), lpath);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a buffer to hold the ASP file in-memory
|
||||
*/
|
||||
len = sbuf.size * sizeof(char);
|
||||
if ((rbuf = balloc(B_L, len + 1)) == NULL) {
|
||||
websError(wp, 200, T("Can't get memory"));
|
||||
goto done;
|
||||
}
|
||||
rbuf[len] = '\0';
|
||||
|
||||
if (websPageReadData(wp, rbuf, len) != len) {
|
||||
websError(wp, 200, T("Cant read %s"), lpath);
|
||||
goto done;
|
||||
}
|
||||
websPageClose(wp);
|
||||
|
||||
/*
|
||||
* Convert to UNICODE if necessary.
|
||||
*/
|
||||
if ((buf = ballocAscToUni(rbuf, len)) == NULL) {
|
||||
websError(wp, 200, T("Can't get memory"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan for the next "<%"
|
||||
*/
|
||||
last = buf;
|
||||
rc = 0;
|
||||
while (rc == 0 && *last && ((nextp = gstrstr(last, T("<%"))) != NULL)) {
|
||||
websWriteBlock(wp, last, (nextp - last));
|
||||
nextp = skipWhite(nextp + 2);
|
||||
|
||||
/*
|
||||
* Decode the language
|
||||
*/
|
||||
token = T("language");
|
||||
|
||||
if ((lang = strtokcmp(nextp, token)) != NULL) {
|
||||
if ((cp = strtokcmp(lang, T("=javascript"))) != NULL) {
|
||||
engine = EMF_SCRIPT_EJSCRIPT;
|
||||
} else {
|
||||
cp = nextp;
|
||||
}
|
||||
nextp = cp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find tailing bracket and then evaluate the script
|
||||
*/
|
||||
if ((ep = gstrstr(nextp, T("%>"))) != NULL) {
|
||||
|
||||
*ep = '\0';
|
||||
last = ep + 2;
|
||||
nextp = skipWhite(nextp);
|
||||
/*
|
||||
* Handle backquoted newlines
|
||||
*/
|
||||
for (cp = nextp; *cp; ) {
|
||||
if (*cp == '\\' && (cp[1] == '\r' || cp[1] == '\n')) {
|
||||
*cp++ = ' ';
|
||||
while (*cp == '\r' || *cp == '\n') {
|
||||
*cp++ = ' ';
|
||||
}
|
||||
} else {
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now call the relevant script engine. Output is done directly
|
||||
* by the ASP script procedure by calling websWrite()
|
||||
*/
|
||||
if (*nextp) {
|
||||
result = NULL;
|
||||
if (engine == EMF_SCRIPT_EJSCRIPT) {
|
||||
rc = scriptEval(engine, nextp, &result, ejid);
|
||||
} else {
|
||||
rc = scriptEval(engine, nextp, &result, (int) wp);
|
||||
}
|
||||
if (rc < 0) {
|
||||
/*
|
||||
* On an error, discard all output accumulated so far
|
||||
* and store the error in the result buffer. Be careful if the
|
||||
* user has called websError() already.
|
||||
*/
|
||||
if (websValid(wp)) {
|
||||
if (result) {
|
||||
websWrite(wp, T("<h2><b>ASP Error: %s</b></h2>\n"),
|
||||
result);
|
||||
websWrite(wp, T("<pre>%s</pre>"), nextp);
|
||||
bfree(B_L, result);
|
||||
} else {
|
||||
websWrite(wp, T("<h2><b>ASP Error</b></h2>\n%s\n"),
|
||||
nextp);
|
||||
}
|
||||
websWrite(wp, T("</body></html>\n"));
|
||||
rc = 0;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
websError(wp, 200, T("Unterminated script in %s: \n"), lpath);
|
||||
rc = -1;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Output any trailing HTML page text
|
||||
*/
|
||||
if (last && *last && rc == 0) {
|
||||
websWriteBlock(wp, last, gstrlen(last));
|
||||
}
|
||||
rc = 0;
|
||||
|
||||
/*
|
||||
* Common exit and cleanup
|
||||
*/
|
||||
done:
|
||||
if (websValid(wp)) {
|
||||
websPageClose(wp);
|
||||
if (ejid >= 0) {
|
||||
ejCloseEngine(ejid);
|
||||
}
|
||||
}
|
||||
bfreeSafe(B_L, buf);
|
||||
bfreeSafe(B_L, rbuf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Define an ASP Ejscript function. Bind an ASP name to a C procedure.
|
||||
*/
|
||||
|
||||
int websAspDefine(char_t *name,
|
||||
int (*fn)(int ejid, webs_t wp, int argc, char_t **argv))
|
||||
{
|
||||
return ejSetGlobalFunctionDirect(websAspFunctions, name,
|
||||
(int (*)(int, void*, int, char_t**)) fn);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Asp write command. This implemements <% write("text"); %> command
|
||||
*/
|
||||
|
||||
int websAspWrite(int ejid, webs_t wp, int argc, char_t **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
a_assert(websValid(wp));
|
||||
|
||||
for (i = 0; i < argc; ) {
|
||||
a_assert(argv);
|
||||
if (websWriteBlock(wp, argv[i], gstrlen(argv[i])) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (++i < argc) {
|
||||
if (websWriteBlock(wp, T(" "), 2) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* strtokcmp -- Find s2 in s1. We skip leading white space in s1.
|
||||
* Return a pointer to the location in s1 after s2 ends.
|
||||
*/
|
||||
|
||||
static char_t *strtokcmp(char_t *s1, char_t *s2)
|
||||
{
|
||||
int len;
|
||||
|
||||
s1 = skipWhite(s1);
|
||||
len = gstrlen(s2);
|
||||
for (len = gstrlen(s2); len > 0 && (tolower(*s1) == tolower(*s2)); len--) {
|
||||
if (*s2 == '\0') {
|
||||
return s1;
|
||||
}
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
if (len == 0) {
|
||||
return s1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Skip white space
|
||||
*/
|
||||
|
||||
static char_t *skipWhite(char_t *s)
|
||||
{
|
||||
a_assert(s);
|
||||
|
||||
if (s == NULL) {
|
||||
return s;
|
||||
}
|
||||
while (*s && gisspace(*s)) {
|
||||
s++;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,967 +0,0 @@
|
||||
/*
|
||||
* balloc.c -- Block allocation module
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* This module implements a very fast block allocation scheme suitable for
|
||||
* ROMed environments. It maintains block class queues for rapid allocation
|
||||
* and minimal fragmentation. This module does not coalesce blocks. The
|
||||
* storage space may be populated statically or via the traditional malloc
|
||||
* mechanisms. Large blocks greater than the maximum class size may be
|
||||
* allocated from the O/S or run-time system via malloc. To permit the use
|
||||
* of malloc, call bopen with flags set to B_USE_MALLOC (this is the default).
|
||||
* It is recommended that bopen be called first thing in the application.
|
||||
* If it is not, it will be called with default values on the first call to
|
||||
* balloc(). Note that this code is not designed for multi-threading purposes
|
||||
* and it depends on newly declared variables being initialized to zero.
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#define IN_BALLOC
|
||||
|
||||
#ifdef UEMF
|
||||
#include "uemf.h"
|
||||
#else
|
||||
#include "basic/basicInternal.h"
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef NO_BALLOC
|
||||
/********************************* Defines ************************************/
|
||||
|
||||
/*
|
||||
* Define B_STATS if you wish to track memory block and stack usage
|
||||
*/
|
||||
#ifdef B_STATS
|
||||
/*
|
||||
* Optional statistics
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
long alloc; /* Block allocation calls */
|
||||
long inuse; /* Blocks in use */
|
||||
} bStatsType;
|
||||
|
||||
typedef struct {
|
||||
char_t file[FNAMESIZE];
|
||||
long allocated; /* Bytes currently allocated */
|
||||
long count; /* Current block count */
|
||||
long times; /* Count of alloc attempts */
|
||||
long largest; /* largest allocated here */
|
||||
int q;
|
||||
} bStatsFileType;
|
||||
|
||||
/*
|
||||
* This one is very expensive but great stats
|
||||
*/
|
||||
typedef struct {
|
||||
void *ptr; /* Pointer to memory */
|
||||
bStatsFileType *who; /* Who allocated the memory */
|
||||
} bStatsBlkType;
|
||||
|
||||
static bStatsType bStats[B_MAX_CLASS]; /* Per class stats */
|
||||
static bStatsFileType bStatsFiles[B_MAX_FILES];/* Per file stats */
|
||||
static bStatsBlkType bStatsBlks[B_MAX_BLOCKS];/* Per block stats */
|
||||
static int bStatsBlksMax = 0; /* Max block entry */
|
||||
static int bStatsFilesMax = 0; /* Max file entry */
|
||||
static int bStatsMemInUse = 0; /* Memory currently in use */
|
||||
static int bStatsBallocInUse = 0; /* Memory currently balloced */
|
||||
static int bStatsMemMax = 0; /* Max memory ever used */
|
||||
static int bStatsBallocMax = 0; /* Max memory ever balloced */
|
||||
static void *bStackMin = (void*) -1;/* Miniumum stack position */
|
||||
static void *bStackStart; /* Starting stack position */
|
||||
static int bStatsMemMalloc = 0; /* Malloced memory */
|
||||
#endif /* B_STATS */
|
||||
|
||||
/*
|
||||
* ROUNDUP4(size) returns the next higher integer value of size that is
|
||||
* divisible by 4, or the value of size if size is divisible by 4.
|
||||
* ROUNDUP4() is used in aligning memory allocations on 4-byte boundaries.
|
||||
*
|
||||
* Note: ROUNDUP4() is only required on some operating systems (IRIX).
|
||||
*/
|
||||
|
||||
#define ROUNDUP4(size) ((size) % 4) ? (size) + (4 - ((size) % 4)) : (size)
|
||||
|
||||
/********************************** Locals ************************************/
|
||||
/*
|
||||
* bQhead blocks are created as the original memory allocation is freed up.
|
||||
* See bfree.
|
||||
*/
|
||||
static bType *bQhead[B_MAX_CLASS]; /* Per class block q head */
|
||||
static char *bFreeBuf; /* Pointer to free memory */
|
||||
static char *bFreeNext; /* Pointer to next free mem */
|
||||
static int bFreeSize; /* Size of free memory */
|
||||
static int bFreeLeft; /* Size of free left for use */
|
||||
static int bFlags = B_USE_MALLOC; /* Default to auto-malloc */
|
||||
static int bopenCount = 0; /* Num tasks using balloc */
|
||||
|
||||
/*************************** Forward Declarations *****************************/
|
||||
|
||||
#ifdef B_STATS
|
||||
static void bStatsAlloc(B_ARGS_DEC, void *ptr, int q, int size);
|
||||
static void bStatsFree(B_ARGS_DEC, void *ptr, int q, int size);
|
||||
static void bstatsWrite(int handle, char_t *fmt, ...);
|
||||
static int bStatsFileSort(const void *cp1, const void *cp2);
|
||||
#endif /* B_STATS */
|
||||
|
||||
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
|
||||
static void bFillBlock(void *buf, int bufsize);
|
||||
#endif
|
||||
|
||||
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
|
||||
static void verifyUsedBlock(bType *bp, int q);
|
||||
static void verifyFreeBlock(bType *bp, int q);
|
||||
void verifyBallocSpace();
|
||||
#endif
|
||||
|
||||
static int ballocGetSize(int size, int *q);
|
||||
|
||||
/********************************** Code **************************************/
|
||||
/*
|
||||
* Initialize the balloc module. bopen should be called the very first thing
|
||||
* after the application starts and bclose should be called the last thing
|
||||
* before exiting. If bopen is not called, it will be called on the first
|
||||
* allocation with default values. "buf" points to memory to use of size
|
||||
* "bufsize". If buf is NULL, memory is allocated using malloc. flags may
|
||||
* be set to B_USE_MALLOC if using malloc is okay. This routine will allocate
|
||||
* an initial buffer of size bufsize for use by the application.
|
||||
*/
|
||||
|
||||
int bopen(void *buf, int bufsize, int flags)
|
||||
{
|
||||
bFlags = flags;
|
||||
|
||||
#ifdef BASTARD_TESTING
|
||||
srand(time(0L));
|
||||
#endif /* BASTARD_TESTING */
|
||||
|
||||
/*
|
||||
* If bopen already called by a shared process, just increment the count
|
||||
* and return;
|
||||
*/
|
||||
if (++bopenCount > 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (buf == NULL) {
|
||||
if (bufsize == 0) {
|
||||
bufsize = B_DEFAULT_MEM;
|
||||
}
|
||||
#ifdef IRIX
|
||||
bufsize = ROUNDUP4(bufsize);
|
||||
#endif
|
||||
if ((buf = malloc(bufsize)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
#ifdef B_STATS
|
||||
bStatsMemMalloc += bufsize;
|
||||
#endif
|
||||
} else {
|
||||
bFlags |= B_USER_BUF;
|
||||
}
|
||||
|
||||
bFreeSize = bFreeLeft = bufsize;
|
||||
bFreeBuf = bFreeNext = buf;
|
||||
memset(bQhead, 0, sizeof(bQhead));
|
||||
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
|
||||
bFillBlock(buf, bufsize);
|
||||
#endif
|
||||
#ifdef B_STATS
|
||||
bStackStart = &buf;
|
||||
#endif
|
||||
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
|
||||
verifyFreeBlock(buf, bufsize);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Close down the balloc module and free all malloced memory.
|
||||
*/
|
||||
|
||||
void bclose()
|
||||
{
|
||||
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
|
||||
verifyBallocSpace();
|
||||
#endif
|
||||
if (--bopenCount <= 0 && !(bFlags & B_USER_BUF)) {
|
||||
free(bFreeBuf);
|
||||
bopenCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Allocate a block of the requested size. First check the block
|
||||
* queues for a suitable one.
|
||||
*/
|
||||
|
||||
void *balloc(B_ARGS_DEC, int size)
|
||||
{
|
||||
bType *bp;
|
||||
int q, memSize;
|
||||
|
||||
/*
|
||||
* Call bopen with default values if the application has not yet done so
|
||||
*/
|
||||
if (bFreeBuf == NULL) {
|
||||
if (bopen(NULL, B_DEFAULT_MEM, 0) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
|
||||
verifyBallocSpace();
|
||||
#endif
|
||||
if (size < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef BASTARD_TESTING
|
||||
if (rand() == 0x7fff) {
|
||||
return NULL;
|
||||
}
|
||||
#endif /* BASTARD_TESTING */
|
||||
|
||||
|
||||
memSize = ballocGetSize(size, &q);
|
||||
|
||||
if (q >= B_MAX_CLASS) {
|
||||
/*
|
||||
* Size if bigger than the maximum class. Malloc if use has been okayed
|
||||
*/
|
||||
if (bFlags & B_USE_MALLOC) {
|
||||
#ifdef B_STATS
|
||||
bstats(0, NULL);
|
||||
#endif
|
||||
#ifdef IRIX
|
||||
memSize = ROUNDUP4(memSize);
|
||||
#endif
|
||||
bp = (bType*) malloc(memSize);
|
||||
if (bp == NULL) {
|
||||
traceRaw(T("B: malloc failed\n"));
|
||||
return NULL;
|
||||
}
|
||||
#ifdef B_STATS
|
||||
bStatsMemMalloc += memSize;
|
||||
#endif
|
||||
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
|
||||
bFillBlock(bp, memSize);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
traceRaw(T("B: malloc failed\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* the u.size is the actual size allocated for data
|
||||
*/
|
||||
bp->u.size = memSize - sizeof(bType);
|
||||
bp->flags = B_MALLOCED;
|
||||
|
||||
} else if ((bp = bQhead[q]) != NULL) {
|
||||
/*
|
||||
* Take first block off the relevant q if non-empty
|
||||
*/
|
||||
bQhead[q] = bp->u.next;
|
||||
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
|
||||
verifyFreeBlock(bp, q);
|
||||
#endif
|
||||
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
|
||||
bFillBlock(bp, memSize);
|
||||
#endif
|
||||
bp->u.size = memSize - sizeof(bType);
|
||||
bp->flags = 0;
|
||||
|
||||
} else {
|
||||
if (bFreeLeft > memSize) {
|
||||
/*
|
||||
* The q was empty, and the free list has spare memory so
|
||||
* create a new block out of the primary free block
|
||||
*/
|
||||
bp = (bType*) bFreeNext;
|
||||
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
|
||||
verifyFreeBlock(bp, q);
|
||||
#endif
|
||||
bFreeNext += memSize;
|
||||
bFreeLeft -= memSize;
|
||||
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
|
||||
bFillBlock(bp, memSize);
|
||||
#endif
|
||||
bp->u.size = memSize - sizeof(bType);
|
||||
bp->flags = 0;
|
||||
|
||||
} else if (bFlags & B_USE_MALLOC) {
|
||||
#ifdef B_STATS
|
||||
static int once = 0;
|
||||
if (once++ == 0) {
|
||||
bstats(0, NULL);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Nothing left on the primary free list, so malloc a new block
|
||||
*/
|
||||
#ifdef IRIX
|
||||
memSize = ROUNDUP4(memSize);
|
||||
#endif
|
||||
if ((bp = (bType*) malloc(memSize)) == NULL) {
|
||||
traceRaw(T("B: malloc failed\n"));
|
||||
return NULL;
|
||||
}
|
||||
#ifdef B_STATS
|
||||
bStatsMemMalloc += memSize;
|
||||
#endif
|
||||
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
|
||||
bFillBlock(bp, memSize);
|
||||
#endif
|
||||
bp->u.size = memSize - sizeof(bType);
|
||||
bp->flags = B_MALLOCED;
|
||||
|
||||
} else {
|
||||
traceRaw(T("B: malloc failed\n"));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef B_STATS
|
||||
bStatsAlloc(B_ARGS, bp, q, memSize);
|
||||
#endif
|
||||
bp->flags |= B_INTEGRITY;
|
||||
|
||||
/*
|
||||
* The following is a good place to put a breakpoint when trying to reduce
|
||||
* determine and reduce maximum memory use.
|
||||
*/
|
||||
#if 0
|
||||
#ifdef B_STATS
|
||||
if (bStatsBallocInUse == bStatsBallocMax) {
|
||||
bstats(0, NULL);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return (void*) ((char*) bp + sizeof(bType));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Free a block back to the relevant free q. We don't free back to the O/S
|
||||
* or run time system unless the block is greater than the maximum class size.
|
||||
* We also do not coalesce blocks.
|
||||
*/
|
||||
|
||||
void bfree(B_ARGS_DEC, void *mp)
|
||||
{
|
||||
bType *bp;
|
||||
int q, memSize;
|
||||
|
||||
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
|
||||
verifyBallocSpace();
|
||||
#endif
|
||||
bp = (bType*) ((char*) mp - sizeof(bType));
|
||||
|
||||
a_assert((bp->flags & B_INTEGRITY_MASK) == B_INTEGRITY);
|
||||
|
||||
if ((bp->flags & B_INTEGRITY_MASK) != B_INTEGRITY) {
|
||||
return;
|
||||
}
|
||||
|
||||
memSize = ballocGetSize(bp->u.size, &q);
|
||||
|
||||
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
|
||||
verifyUsedBlock(bp,q);
|
||||
#endif
|
||||
#ifdef B_STATS
|
||||
bStatsFree(B_ARGS, bp, q, bp->u.size+sizeof(bType));
|
||||
#endif
|
||||
if (bp->flags & B_MALLOCED) {
|
||||
free(bp);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
|
||||
bFillBlock(bp, memSize);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Simply link onto the head of the relevant q
|
||||
*/
|
||||
bp->u.next = bQhead[q];
|
||||
bQhead[q] = bp;
|
||||
|
||||
bp->flags = B_FILL_WORD;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Safe free
|
||||
*/
|
||||
|
||||
void bfreeSafe(B_ARGS_DEC, void *mp)
|
||||
{
|
||||
if (mp) {
|
||||
bfree(B_ARGS, mp);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
#ifdef UNICODE
|
||||
/*
|
||||
* Duplicate a string, allow NULL pointers and then dup an empty string.
|
||||
*/
|
||||
|
||||
char *bstrdupA(B_ARGS_DEC, char *s)
|
||||
{
|
||||
char *cp;
|
||||
int len;
|
||||
|
||||
if (s == NULL) {
|
||||
s = "";
|
||||
}
|
||||
len = strlen(s) + 1;
|
||||
if (cp = balloc(B_ARGS, len)) {
|
||||
strcpy(cp, s);
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
|
||||
#endif /* UNICODE */
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Duplicate an ascii string, allow NULL pointers and then dup an empty string.
|
||||
* If UNICODE, bstrdup above works with wide chars, so we need this routine
|
||||
* for ascii strings.
|
||||
*/
|
||||
|
||||
char_t *bstrdup(B_ARGS_DEC, char_t *s)
|
||||
{
|
||||
char_t *cp;
|
||||
int len;
|
||||
|
||||
if (s == NULL) {
|
||||
s = T("");
|
||||
}
|
||||
len = gstrlen(s) + 1;
|
||||
if ((cp = balloc(B_ARGS, len * sizeof(char_t))) != NULL) {
|
||||
gstrcpy(cp, s);
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Reallocate a block. Allow NULL pointers and just do a malloc.
|
||||
* Note: if the realloc fails, we return NULL and the previous buffer is
|
||||
* preserved.
|
||||
*/
|
||||
|
||||
void *brealloc(B_ARGS_DEC, void *mp, int newsize)
|
||||
{
|
||||
bType *bp;
|
||||
void *newbuf;
|
||||
|
||||
if (mp == NULL) {
|
||||
return balloc(B_ARGS, newsize);
|
||||
}
|
||||
bp = (bType*) ((char*) mp - sizeof(bType));
|
||||
a_assert((bp->flags & B_INTEGRITY_MASK) == B_INTEGRITY);
|
||||
|
||||
/*
|
||||
* If the allocated memory already has enough room just return the previously
|
||||
* allocated address.
|
||||
*/
|
||||
if (bp->u.size >= newsize) {
|
||||
return mp;
|
||||
}
|
||||
if ((newbuf = balloc(B_ARGS, newsize)) != NULL) {
|
||||
memcpy(newbuf, mp, bp->u.size);
|
||||
bfree(B_ARGS, mp);
|
||||
}
|
||||
return newbuf;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Find the size of the block to be balloc'ed. It takes in a size, finds the
|
||||
* smallest binary block it fits into, adds an overhead amount and returns.
|
||||
* q is the binary size used to keep track of block sizes in use. Called
|
||||
* from both balloc and bfree.
|
||||
*/
|
||||
|
||||
static int ballocGetSize(int size, int *q)
|
||||
{
|
||||
int mask;
|
||||
|
||||
mask = (size == 0) ? 0 : (size-1) >> B_SHIFT;
|
||||
for (*q = 0; mask; mask >>= 1) {
|
||||
*q = *q + 1;
|
||||
}
|
||||
return ((1 << (B_SHIFT + *q)) + sizeof(bType));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
|
||||
/*
|
||||
* Fill the block (useful during development to catch zero fill assumptions)
|
||||
*/
|
||||
|
||||
static void bFillBlock(void *buf, int bufsize)
|
||||
{
|
||||
memset(buf, B_FILL_CHAR, bufsize);
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
#ifdef B_STATS
|
||||
/*
|
||||
* Statistics. Do output via calling the writefn callback function with
|
||||
* "handle" as the output file handle.
|
||||
*/
|
||||
|
||||
void bstats(int handle, void (*writefn)(int handle, char_t *fmt, ...))
|
||||
{
|
||||
bStatsFileType *fp, *files;
|
||||
bStatsBlkType *blkp;
|
||||
bType *bp;
|
||||
char_t *cp;
|
||||
int q, count, mem, total, len;
|
||||
static int recurseProtect = 0;
|
||||
|
||||
if (recurseProtect++ > 0) {
|
||||
recurseProtect--;
|
||||
return;
|
||||
}
|
||||
|
||||
if (writefn == NULL) {
|
||||
writefn = bstatsWrite;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print stats for each memory block
|
||||
*/
|
||||
(*writefn)(handle, T("\nMemory Stats\n"));
|
||||
|
||||
/*
|
||||
* The following tabular format is now used for the output.
|
||||
* Q Size Free Bytes Inuse Bytes Allocs
|
||||
* dd ddddd ddd ddddd dddd ddddd dddd
|
||||
*/
|
||||
(*writefn)(handle, " Q Size Free Bytes Inuse Bytes Allocs\n");
|
||||
|
||||
total = 0;
|
||||
for (q = 0; q < B_MAX_CLASS; q++) {
|
||||
count = 0;
|
||||
for (bp = bQhead[q]; bp; bp = bp->u.next) {
|
||||
count++;
|
||||
}
|
||||
mem = count * (1 << (q + B_SHIFT));
|
||||
total += mem;
|
||||
(*writefn)(handle,
|
||||
T("%2d %5d %4d %6d %4d %5d %4d\n"),
|
||||
q, 1 << (q + B_SHIFT), count, mem, bStats[q].inuse,
|
||||
bStats[q].inuse * (1 << (q + B_SHIFT)), bStats[q].alloc);
|
||||
}
|
||||
|
||||
(*writefn)(handle, T("\n"));
|
||||
|
||||
/*
|
||||
* Print summary stats
|
||||
*
|
||||
* bFreeSize Initial memory reserved with bopen call
|
||||
* bStatsMemMalloc memory from calls to system MALLOC
|
||||
* bStatsMemMax
|
||||
* bStatsBallocMax largest amount of memory from balloc calls
|
||||
* bStatsMemInUse
|
||||
* bStatsBallocInUse present balloced memory being used
|
||||
* bStatsBlksMax);
|
||||
* bStackStart
|
||||
* bStackMin);
|
||||
* total);
|
||||
* bFreeLeft);
|
||||
*
|
||||
*/
|
||||
(*writefn)(handle, T("Initial free list size %7d\n"), bFreeSize);
|
||||
(*writefn)(handle, T("Max memory malloced %7d\n"), bStatsMemMalloc);
|
||||
(*writefn)(handle, T("Max memory ever used %7d\n"), bStatsMemMax);
|
||||
(*writefn)(handle, T("Max memory ever balloced %7d\n"), bStatsBallocMax);
|
||||
(*writefn)(handle, T("Memory currently in use %7d\n"), bStatsMemInUse);
|
||||
(*writefn)(handle, T("Memory currently balloced %7d\n"), bStatsBallocInUse);
|
||||
(*writefn)(handle, T("Max blocks allocated %7d\n"), bStatsBlksMax);
|
||||
(*writefn)(handle, T("Maximum stack used %7d\n"),
|
||||
(int) bStackStart - (int) bStackMin);
|
||||
|
||||
(*writefn)(handle, T("Free memory on all queues %7d\n"), total);
|
||||
(*writefn)(handle, T("Free list buffer left %7d\n"), bFreeLeft);
|
||||
(*writefn)(handle, T("Total free memory %7d\n"), bFreeLeft + total);
|
||||
|
||||
/*
|
||||
* Print per file allocation stats. Sort the copied table.
|
||||
*/
|
||||
len = sizeof(bStatsFileType) * B_MAX_FILES;
|
||||
files = malloc(len);
|
||||
if (files == NULL) {
|
||||
(*writefn)(handle, T("Can't allocate stats memory\n"));
|
||||
recurseProtect--;
|
||||
return;
|
||||
}
|
||||
memcpy(files, bStatsFiles, len);
|
||||
qsort(files, bStatsFilesMax, sizeof(bStatsFileType), bStatsFileSort);
|
||||
|
||||
(*writefn)(handle, T("\nMemory Currently Allocated\n"));
|
||||
total = 0;
|
||||
(*writefn)(handle,
|
||||
T(" bytes, blocks in use, total times,")
|
||||
T("largest, q\n"));
|
||||
|
||||
for (fp = files; fp < &files[bStatsFilesMax]; fp++) {
|
||||
if (fp->file[0]) {
|
||||
(*writefn)(handle, T("%18s, %7d, %5d, %6d, %7d,%4d\n"),
|
||||
fp->file, fp->allocated, fp->count, fp->times, fp->largest,
|
||||
fp->q);
|
||||
total += fp->allocated;
|
||||
}
|
||||
}
|
||||
(*writefn)(handle, T("\nTotal allocated %7d\n\n"), total);
|
||||
|
||||
/*
|
||||
* Dump the actual strings
|
||||
*/
|
||||
(*writefn)(handle, T("\nStrings\n"));
|
||||
for (blkp = &bStatsBlks[bStatsBlksMax - 1]; blkp >= bStatsBlks; blkp--) {
|
||||
if (blkp->ptr) {
|
||||
cp = (char_t*) ((char*) blkp->ptr + sizeof(bType));
|
||||
fp = blkp->who;
|
||||
if (gisalnum(*cp)) {
|
||||
(*writefn)(handle, T("%-50s allocated by %s\n"), cp,
|
||||
fp->file);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(files);
|
||||
recurseProtect--;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* File sort function. Used to sort per file stats
|
||||
*/
|
||||
|
||||
static int bStatsFileSort(const void *cp1, const void *cp2)
|
||||
{
|
||||
bStatsFileType *s1, *s2;
|
||||
|
||||
s1 = (bStatsFileType*) cp1;
|
||||
s2 = (bStatsFileType*) cp2;
|
||||
|
||||
if (s1->allocated < s2->allocated)
|
||||
return -1;
|
||||
else if (s1->allocated == s2->allocated)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Accumulate allocation statistics
|
||||
*/
|
||||
|
||||
static void bStatsAlloc(B_ARGS_DEC, void *ptr, int q, int size)
|
||||
{
|
||||
int memSize;
|
||||
bStatsFileType *fp;
|
||||
bStatsBlkType *bp;
|
||||
char_t name[FNAMESIZE + 10];
|
||||
|
||||
gsprintf(name, T("%s:%d"), B_ARGS);
|
||||
|
||||
bStats[q].alloc++;
|
||||
bStats[q].inuse++;
|
||||
bStatsMemInUse += size;
|
||||
if (bStatsMemInUse > bStatsMemMax) {
|
||||
bStatsMemMax = bStatsMemInUse;
|
||||
}
|
||||
memSize = (1 << (B_SHIFT + q)) + sizeof(bType);
|
||||
bStatsBallocInUse += memSize;
|
||||
if (bStatsBallocInUse > bStatsBallocMax) {
|
||||
bStatsBallocMax = bStatsBallocInUse;
|
||||
}
|
||||
|
||||
/*
|
||||
* Track maximum stack usage. Assumes a stack growth down. Approximate as
|
||||
* we only measure this on block allocation.
|
||||
*/
|
||||
if ((void*) &file < bStackMin) {
|
||||
bStackMin = (void*) &file;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the file and adjust the stats for this file
|
||||
*/
|
||||
for (fp = bStatsFiles; fp < &bStatsFiles[bStatsFilesMax]; fp++) {
|
||||
if (fp->file[0] == file[0] && gstrcmp(fp->file, name) == 0) {
|
||||
fp->allocated += size;
|
||||
fp->count++;
|
||||
fp->times++;
|
||||
if (fp->largest < size) {
|
||||
fp->largest = size;
|
||||
fp->q = q;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* New entry: find the first free slot and create a new entry
|
||||
*/
|
||||
if (fp >= &bStatsFiles[bStatsFilesMax]) {
|
||||
for (fp = bStatsFiles; fp < &bStatsFiles[B_MAX_FILES]; fp++) {
|
||||
if (fp->file[0] == '\0') {
|
||||
gstrncpy(fp->file, name, TSZ(fp->file));
|
||||
fp->allocated += size;
|
||||
fp->count++;
|
||||
fp->times++;
|
||||
fp->largest = size;
|
||||
fp->q = q;
|
||||
if ((fp - bStatsFiles) >= bStatsFilesMax) {
|
||||
bStatsFilesMax = (fp - bStatsFiles) + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the per block stats. Allocate a new slot.
|
||||
*/
|
||||
for (bp = bStatsBlks; bp < &bStatsBlks[B_MAX_BLOCKS]; bp++) {
|
||||
if (bp->ptr == NULL) {
|
||||
bp->ptr = ptr;
|
||||
bp->who = fp;
|
||||
if ((bp - bStatsBlks) >= bStatsBlksMax) {
|
||||
bStatsBlksMax = (bp - bStatsBlks) + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Free statistics
|
||||
*/
|
||||
|
||||
static void bStatsFree(B_ARGS_DEC, void *ptr, int q, int size)
|
||||
{
|
||||
int memSize;
|
||||
bStatsFileType *fp;
|
||||
bStatsBlkType *bp;
|
||||
|
||||
memSize = (1 << (B_SHIFT + q)) + sizeof(bType);
|
||||
bStatsMemInUse -= size;
|
||||
bStatsBallocInUse -= memSize;
|
||||
bStats[q].inuse--;
|
||||
|
||||
/*
|
||||
* Update the per block stats. Try from the end first
|
||||
*/
|
||||
for (bp = &bStatsBlks[bStatsBlksMax - 1]; bp >= bStatsBlks; bp--) {
|
||||
if (bp->ptr == ptr) {
|
||||
bp->ptr = NULL;
|
||||
fp = bp->who;
|
||||
bp->who = NULL;
|
||||
fp->allocated -= size;
|
||||
fp->count--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Default output function. Just send to trace channel.
|
||||
*/
|
||||
|
||||
#undef sprintf
|
||||
static void bstatsWrite(int handle, char_t *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char_t buf[BUF_MAX];
|
||||
|
||||
va_start(args, fmt);
|
||||
vsprintf(buf, fmt, args);
|
||||
va_end(args);
|
||||
traceRaw(buf);
|
||||
}
|
||||
|
||||
|
||||
#else /* not B_STATS */
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Dummy bstats for external calls that aren't protected by #if B_STATS.
|
||||
*/
|
||||
|
||||
void bstats(int handle, void (*writefn)(int handle, char_t *fmt, ...))
|
||||
{
|
||||
}
|
||||
#endif /* B_STATS */
|
||||
|
||||
/******************************************************************************/
|
||||
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
|
||||
/*
|
||||
* The following routines verify the integrity of the balloc memory space.
|
||||
* These functions use the B_FILL feature. Corruption is defined
|
||||
* as bad integrity flags in allocated blocks or data other than B_FILL_CHAR
|
||||
* being found anywhere in the space which is unallocated and that is not a
|
||||
* next pointer in the free queues. a_assert is called if any corruption is
|
||||
* found. CAUTION: These functions add severe processing overhead and should
|
||||
* only be used when searching for a tough corruption problem.
|
||||
*/
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* verifyUsedBlock verifies that a block which was previously allocated is
|
||||
* still uncorrupted.
|
||||
*/
|
||||
|
||||
static void verifyUsedBlock(bType *bp, int q)
|
||||
{
|
||||
int memSize, size;
|
||||
char *p;
|
||||
|
||||
memSize = (1 << (B_SHIFT + q)) + sizeof(bType);
|
||||
a_assert((bp->flags & ~B_MALLOCED) == B_INTEGRITY);
|
||||
size = bp->u.size;
|
||||
for (p = ((char *)bp)+sizeof(bType)+size; p < ((char*)bp)+memSize; p++) {
|
||||
a_assert(*p == B_FILL_CHAR);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* verifyFreeBlock verifies that a previously free'd block in one of the queues
|
||||
* is still uncorrupted.
|
||||
*/
|
||||
|
||||
static void verifyFreeBlock(bType *bp, int q)
|
||||
{
|
||||
int memSize;
|
||||
char *p;
|
||||
|
||||
memSize = (1 << (B_SHIFT + q)) + sizeof(bType);
|
||||
for (p = ((char *)bp)+sizeof(void*); p < ((char*)bp)+memSize; p++) {
|
||||
a_assert(*p == B_FILL_CHAR);
|
||||
}
|
||||
bp = (bType *)p;
|
||||
a_assert((bp->flags & ~B_MALLOCED) == B_INTEGRITY ||
|
||||
bp->flags == B_FILL_WORD);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* verifyBallocSpace reads through the entire balloc memory space and
|
||||
* verifies that all allocated blocks are uncorrupted and that, with the
|
||||
* exception of free list next pointers, all other unallocated space is
|
||||
* filled with B_FILL_CHAR.
|
||||
*/
|
||||
|
||||
void verifyBallocSpace()
|
||||
{
|
||||
int q;
|
||||
char *p;
|
||||
bType *bp;
|
||||
|
||||
/*
|
||||
* First verify all the free blocks.
|
||||
*/
|
||||
for (q = 0; q < B_MAX_CLASS; q++) {
|
||||
for (bp = bQhead[q]; bp != NULL; bp = bp->u.next) {
|
||||
verifyFreeBlock(bp, q);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now verify other space
|
||||
*/
|
||||
p = bFreeBuf;
|
||||
while (p < (bFreeBuf + bFreeSize)) {
|
||||
bp = (bType *)p;
|
||||
if (bp->u.size > 0xFFFFF) {
|
||||
p += sizeof(bp->u);
|
||||
while (p < (bFreeBuf + bFreeSize) && *p == B_FILL_CHAR) {
|
||||
p++;
|
||||
}
|
||||
} else {
|
||||
a_assert(((bp->flags & ~B_MALLOCED) == B_INTEGRITY) ||
|
||||
bp->flags == B_FILL_WORD);
|
||||
p += (sizeof(bType) + bp->u.size);
|
||||
while (p < (bFreeBuf + bFreeSize) && *p == B_FILL_CHAR) {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* B_VERIFY_CAUSES_SEVERE_OVERHEAD */
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#else /* NO_BALLOC */
|
||||
int bopen(void *buf, int bufsize, int flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void bclose()
|
||||
{
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void bstats(int handle, void (*writefn)(int handle, char_t *fmt, ...))
|
||||
{
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
char_t *bstrdupNoBalloc(char_t *s)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
if (s) {
|
||||
return wcsdup(s);
|
||||
} else {
|
||||
return wcsdup(T(""));
|
||||
}
|
||||
#else
|
||||
return bstrdupANoBalloc(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
char *bstrdupANoBalloc(char *s)
|
||||
{
|
||||
char* buf;
|
||||
|
||||
if (s == NULL) {
|
||||
s = "";
|
||||
}
|
||||
buf = malloc(strlen(s)+1);
|
||||
strcpy(buf, s);
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif /* NO_BALLOC */
|
||||
/******************************************************************************/
|
||||
@@ -1,331 +0,0 @@
|
||||
/*
|
||||
* cgi.c -- CGI processing (for the GoAhead Web server
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/********************************** Description *******************************/
|
||||
/*
|
||||
* This module implements the /cgi-bin handler. CGI processing differs from
|
||||
* goforms processing in that each CGI request is executed as a separate
|
||||
* process, rather than within the webserver process. For each CGI request the
|
||||
* environment of the new process must be set to include all the CGI variables
|
||||
* and its standard input and output must be directed to the socket. This
|
||||
* is done using temporary files.
|
||||
*/
|
||||
|
||||
/*********************************** Includes *********************************/
|
||||
#include "wsIntrn.h"
|
||||
#ifdef UEMF
|
||||
#include "uemf.h"
|
||||
#else
|
||||
#include "basic/basicInternal.h"
|
||||
#endif
|
||||
|
||||
/************************************ Locals **********************************/
|
||||
typedef struct { /* Struct for CGI tasks which have completed */
|
||||
webs_t wp; /* pointer to session websRec */
|
||||
char_t *stdIn; /* file desc. for task's temp input fd */
|
||||
char_t *stdOut; /* file desc. for task's temp output fd */
|
||||
char_t *cgiPath; /* path to executable process file */
|
||||
char_t **argp; /* pointer to buf containing argv tokens */
|
||||
char_t **envp; /* pointer to array of environment strings */
|
||||
int handle; /* process handle of the task */
|
||||
long fplacemark; /* seek location for CGI output file */
|
||||
} cgiRec;
|
||||
static cgiRec **cgiList; /* hAlloc chain list of wp's to be closed */
|
||||
static int cgiMax; /* Size of hAlloc list */
|
||||
|
||||
/************************************* Code ***********************************/
|
||||
|
||||
/*
|
||||
* Process a form request. Returns 1 always to indicate it handled the URL
|
||||
*/
|
||||
int websCgiHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg,
|
||||
char_t *url, char_t *path, char_t* query)
|
||||
{
|
||||
cgiRec *cgip;
|
||||
sym_t *s;
|
||||
char_t cgiBuf[FNAMESIZE], *stdIn, *stdOut, cwd[FNAMESIZE];
|
||||
char_t *cp, *cgiName, *cgiPath, **argp, **envp, **ep;
|
||||
int n, envpsize, argpsize, pHandle, cid;
|
||||
a_assert(websValid(wp));
|
||||
a_assert(url && *url);
|
||||
a_assert(path && *path == '/');
|
||||
websStats.cgiHits++;
|
||||
/*
|
||||
* Extract the form name and then build the full path name. The form
|
||||
* name will follow the first '/' in path.
|
||||
*/
|
||||
gstrncpy(cgiBuf, path, TSZ(cgiBuf));
|
||||
if ((cgiName = gstrchr(&cgiBuf[1], '/')) == NULL) {
|
||||
websError(wp, 200, T("Missing CGI name"));
|
||||
return 1;
|
||||
}
|
||||
cgiName++;
|
||||
if ((cp = gstrchr(cgiName, '/')) != NULL) {
|
||||
*cp = '\0';
|
||||
}
|
||||
fmtAlloc(&cgiPath, FNAMESIZE, T("%s/%s/%s"), websGetDefaultDir(),
|
||||
CGI_BIN, cgiName);
|
||||
#ifndef VXWORKS
|
||||
/*
|
||||
* See if the file exists and is executable. If not error out.
|
||||
* Don't do this step for VxWorks, since the module may already
|
||||
* be part of the OS image, rather than in the file system.
|
||||
*/
|
||||
{
|
||||
gstat_t sbuf;
|
||||
if (gstat(cgiPath, &sbuf) != 0 || (sbuf.st_mode & S_IFREG) == 0) {
|
||||
websError(wp, 200, T("CGI process file does not exist"));
|
||||
bfree(B_L, cgiPath);
|
||||
return 1;
|
||||
}
|
||||
#if (defined (WIN) || defined (CE))
|
||||
if (gstrstr(cgiPath, T(".exe")) == NULL &&
|
||||
gstrstr(cgiPath, T(".bat")) == NULL) {
|
||||
#elif (defined (NW))
|
||||
if (gstrstr(cgiPath, T(".nlm")) == NULL) {
|
||||
#else
|
||||
if (gaccess(cgiPath, X_OK) != 0) {
|
||||
#endif /* WIN || CE */
|
||||
websError(wp, 200, T("CGI process file is not executable"));
|
||||
bfree(B_L, cgiPath);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif /* ! VXWORKS */
|
||||
|
||||
|
||||
/*
|
||||
* Get the CWD for resetting after launching the child process CGI
|
||||
*/
|
||||
ggetcwd(cwd, FNAMESIZE);
|
||||
/*
|
||||
* Retrieve the directory of the child process CGI
|
||||
*/
|
||||
if ((cp = gstrrchr(cgiPath, '/')) != NULL) {
|
||||
*cp = '\0';
|
||||
gchdir(cgiPath);
|
||||
*cp = '/';
|
||||
}
|
||||
/*
|
||||
* Build command line arguments. Only used if there is no non-encoded
|
||||
* = character. This is indicative of a ISINDEX query. POST separators
|
||||
* are & and others are +. argp will point to a balloc'd array of
|
||||
* pointers. Each pointer will point to substring within the
|
||||
* query string. This array of string pointers is how the spawn or
|
||||
* exec routines expect command line arguments to be passed. Since
|
||||
* we don't know ahead of time how many individual items there are in
|
||||
* the query string, the for loop includes logic to grow the array
|
||||
* size via brealloc.
|
||||
*/
|
||||
argpsize = 10;
|
||||
argp = balloc(B_L, argpsize * sizeof(char_t *));
|
||||
*argp = cgiPath;
|
||||
n = 1;
|
||||
if (gstrchr(query, '=') == NULL) {
|
||||
websDecodeUrl(query, query, gstrlen(query));
|
||||
for (cp = gstrtok(query, T(" ")); cp != NULL; ) {
|
||||
*(argp+n) = cp;
|
||||
n++;
|
||||
if (n >= argpsize) {
|
||||
argpsize *= 2;
|
||||
argp = brealloc(B_L, argp, argpsize * sizeof(char_t *));
|
||||
}
|
||||
cp = gstrtok(NULL, T(" "));
|
||||
}
|
||||
}
|
||||
*(argp+n) = NULL;
|
||||
/*
|
||||
* Add all CGI variables to the environment strings to be passed
|
||||
* to the spawned CGI process. This includes a few we don't
|
||||
* already have in the symbol table, plus all those that are in
|
||||
* the cgiVars symbol table. envp will point to a balloc'd array of
|
||||
* pointers. Each pointer will point to a balloc'd string containing
|
||||
* the keyword value pair in the form keyword=value. Since we don't
|
||||
* know ahead of time how many environment strings there will be the
|
||||
* for loop includes logic to grow the array size via brealloc.
|
||||
*/
|
||||
envpsize = WEBS_SYM_INIT;
|
||||
envp = balloc(B_L, envpsize * sizeof(char_t *));
|
||||
n = 0;
|
||||
fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"),T("PATH_TRANSLATED"), cgiPath);
|
||||
n++;
|
||||
fmtAlloc(envp+n, FNAMESIZE, T("%s=%s/%s"),T("SCRIPT_NAME"),
|
||||
CGI_BIN, cgiName);
|
||||
n++;
|
||||
fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"),T("REMOTE_USER"), wp->userName);
|
||||
n++;
|
||||
fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"),T("AUTH_TYPE"), wp->authType);
|
||||
n++;
|
||||
for (s = symFirst(wp->cgiVars); s != NULL; s = symNext(wp->cgiVars)) {
|
||||
if (s->content.valid && s->content.type == string &&
|
||||
gstrcmp(s->name.value.string, T("REMOTE_HOST")) != 0 &&
|
||||
gstrcmp(s->name.value.string, T("HTTP_AUTHORIZATION")) != 0) {
|
||||
fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"), s->name.value.string,
|
||||
s->content.value.string);
|
||||
n++;
|
||||
if (n >= envpsize) {
|
||||
envpsize *= 2;
|
||||
envp = brealloc(B_L, envp, envpsize * sizeof(char_t *));
|
||||
}
|
||||
}
|
||||
}
|
||||
*(envp+n) = NULL;
|
||||
/*
|
||||
* Create temporary file name(s) for the child's stdin and stdout.
|
||||
* For POST data the stdin temp file (and name) should already exist.
|
||||
*/
|
||||
if (wp->cgiStdin == NULL) {
|
||||
wp->cgiStdin = websGetCgiCommName();
|
||||
}
|
||||
stdIn = wp->cgiStdin;
|
||||
stdOut = websGetCgiCommName();
|
||||
/*
|
||||
* Now launch the process. If not successful, do the cleanup of resources.
|
||||
* If successful, the cleanup will be done after the process completes.
|
||||
*/
|
||||
if ((pHandle = websLaunchCgiProc(cgiPath, argp, envp, stdIn, stdOut))
|
||||
== -1) {
|
||||
websError(wp, 200, T("failed to spawn CGI task"));
|
||||
for (ep = envp; *ep != NULL; ep++) {
|
||||
bfreeSafe(B_L, *ep);
|
||||
}
|
||||
bfreeSafe(B_L, cgiPath);
|
||||
bfreeSafe(B_L, argp);
|
||||
bfreeSafe(B_L, envp);
|
||||
bfreeSafe(B_L, stdOut);
|
||||
} else {
|
||||
/*
|
||||
* If the spawn was successful, put this wp on a queue to be
|
||||
* checked for completion.
|
||||
*/
|
||||
cid = hAllocEntry((void***) &cgiList, &cgiMax, sizeof(cgiRec));
|
||||
cgip = cgiList[cid];
|
||||
cgip->handle = pHandle;
|
||||
cgip->stdIn = stdIn;
|
||||
cgip->stdOut = stdOut;
|
||||
cgip->cgiPath = cgiPath;
|
||||
cgip->argp = argp;
|
||||
cgip->envp = envp;
|
||||
cgip->wp = wp;
|
||||
cgip->fplacemark = 0;
|
||||
websTimeoutCancel(wp);
|
||||
}
|
||||
/*
|
||||
* Restore the current working directory after spawning child CGI
|
||||
*/
|
||||
gchdir(cwd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Any entry in the cgiList need to be checked to see if it has
|
||||
*/
|
||||
void websCgiGatherOutput (cgiRec *cgip)
|
||||
{
|
||||
gstat_t sbuf;
|
||||
char_t cgiBuf[FNAMESIZE];
|
||||
if ((gstat(cgip->stdOut, &sbuf) == 0) &&
|
||||
(sbuf.st_size > cgip->fplacemark)) {
|
||||
int fdout;
|
||||
fdout = gopen(cgip->stdOut, O_RDONLY | O_BINARY, 0444 );
|
||||
/*
|
||||
* Check to see if any data is available in the
|
||||
* output file and send its contents to the socket.
|
||||
*/
|
||||
if (fdout >= 0) {
|
||||
webs_t wp = cgip->wp;
|
||||
int nRead;
|
||||
/*
|
||||
* Write the HTTP header on our first pass
|
||||
*/
|
||||
if (cgip->fplacemark == 0) {
|
||||
websWrite(wp, T("HTTP/1.0 200 OK\r\n"));
|
||||
}
|
||||
glseek(fdout, cgip->fplacemark, SEEK_SET);
|
||||
while ((nRead = gread(fdout, cgiBuf, FNAMESIZE)) > 0) {
|
||||
websWriteBlock(wp, cgiBuf, nRead);
|
||||
cgip->fplacemark += nRead;
|
||||
}
|
||||
gclose(fdout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Any entry in the cgiList need to be checked to see if it has
|
||||
* completed, and if so, process its output and clean up.
|
||||
*/
|
||||
void websCgiCleanup()
|
||||
{
|
||||
cgiRec *cgip;
|
||||
webs_t wp;
|
||||
char_t **ep;
|
||||
int cid, nTries;
|
||||
for (cid = 0; cid < cgiMax; cid++) {
|
||||
if ((cgip = cgiList[cid]) != NULL) {
|
||||
wp = cgip->wp;
|
||||
websCgiGatherOutput (cgip);
|
||||
if (websCheckCgiProc(cgip->handle) == 0) {
|
||||
/*
|
||||
* We get here if the CGI process has terminated. Clean up.
|
||||
*/
|
||||
nTries = 0;
|
||||
/*
|
||||
* Make sure we didn't miss something during a task switch.
|
||||
* Maximum wait is 100 times 10 msecs (1 second).
|
||||
*/
|
||||
while ((cgip->fplacemark == 0) && (nTries < 100)) {
|
||||
websCgiGatherOutput(cgip);
|
||||
/*
|
||||
* There are some cases when we detect app exit
|
||||
* before the file is ready.
|
||||
*/
|
||||
if (cgip->fplacemark == 0) {
|
||||
#ifdef WIN
|
||||
Sleep(10);
|
||||
#endif /* WIN*/
|
||||
}
|
||||
nTries++;
|
||||
}
|
||||
if (cgip->fplacemark == 0) {
|
||||
websError(wp, 200, T("CGI generated no output"));
|
||||
} else {
|
||||
websDone(wp, 200);
|
||||
}
|
||||
/*
|
||||
* Remove the temporary re-direction files
|
||||
*/
|
||||
gunlink(cgip->stdIn);
|
||||
gunlink(cgip->stdOut);
|
||||
/*
|
||||
* Free all the memory buffers pointed to by cgip.
|
||||
* The stdin file name (wp->cgiStdin) gets freed as
|
||||
* part of websFree().
|
||||
*/
|
||||
cgiMax = hFree((void***) &cgiList, cid);
|
||||
for (ep = cgip->envp; ep != NULL && *ep != NULL; ep++) {
|
||||
bfreeSafe(B_L, *ep);
|
||||
}
|
||||
bfreeSafe(B_L, cgip->cgiPath);
|
||||
bfreeSafe(B_L, cgip->argp);
|
||||
bfreeSafe(B_L, cgip->envp);
|
||||
bfreeSafe(B_L, cgip->stdOut);
|
||||
bfreeSafe(B_L, cgip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/******************************************************************************/
|
||||
@@ -1,431 +0,0 @@
|
||||
/*
|
||||
* default.c -- Default URL handler. Includes support for ASP.
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* This module provides default URL handling and Active Server Page support.
|
||||
*
|
||||
* In many cases we don't check the return code of calls to websWrite as
|
||||
* it is easier, smaller and non-fatal to continue even when the requesting
|
||||
* browser has gone away.
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#include "wsIntrn.h"
|
||||
|
||||
/*********************************** Locals ***********************************/
|
||||
|
||||
static char_t *websDefaultPage; /* Default page name */
|
||||
static char_t *websDefaultDir; /* Default Web page directory */
|
||||
|
||||
/**************************** Forward Declarations ****************************/
|
||||
|
||||
static void websDefaultWriteEvent(webs_t wp);
|
||||
|
||||
/*********************************** Code *************************************/
|
||||
/*
|
||||
* Process a default URL request. This will validate the URL and handle "../"
|
||||
* and will provide support for Active Server Pages. As the handler is the
|
||||
* last handler to run, it always indicates that it has handled the URL
|
||||
* by returning 1.
|
||||
*/
|
||||
|
||||
int websDefaultHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg,
|
||||
char_t *url, char_t *path, char_t *query)
|
||||
{
|
||||
websStatType sbuf;
|
||||
char_t *lpath, *tmp, *date;
|
||||
int bytes, flags, nchars;
|
||||
|
||||
a_assert(websValid(wp));
|
||||
a_assert(url && *url);
|
||||
a_assert(path);
|
||||
a_assert(query);
|
||||
|
||||
/*
|
||||
* Validate the URL and ensure that ".."s don't give access to unwanted files
|
||||
*/
|
||||
flags = websGetRequestFlags(wp);
|
||||
|
||||
if (websValidateUrl(wp, path) < 0) {
|
||||
websError(wp, 500, T("Invalid URL %s"), url);
|
||||
return 1;
|
||||
}
|
||||
lpath = websGetRequestLpath(wp);
|
||||
nchars = gstrlen(lpath) - 1;
|
||||
if (lpath[nchars] == '/' || lpath[nchars] == '\\') {
|
||||
lpath[nchars] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* If the file is a directory, redirect using the nominated default page
|
||||
*/
|
||||
if (websPageIsDirectory(lpath)) {
|
||||
nchars = gstrlen(path);
|
||||
if (path[nchars-1] == '/' || path[nchars-1] == '\\') {
|
||||
path[--nchars] = '\0';
|
||||
}
|
||||
nchars += gstrlen(websDefaultPage) + 2;
|
||||
fmtAlloc(&tmp, nchars, T("%s/%s"), path, websDefaultPage);
|
||||
websRedirect(wp, tmp);
|
||||
bfreeSafe(B_L, tmp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the document. Stat for later use.
|
||||
*/
|
||||
if (websPageOpen(wp, lpath, path, SOCKET_RDONLY | SOCKET_BINARY,
|
||||
0666) < 0) {
|
||||
websError(wp, 400, T("Cannot open URL <b>%s</b>"), url);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (websPageStat(wp, lpath, path, &sbuf) < 0) {
|
||||
websError(wp, 400, T("Cannot stat page for URL <b>%s</b>"), url);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the page has not been modified since the user last received it and it
|
||||
* is not dynamically generated each time (ASP), then optimize request by
|
||||
* sending a 304 Use local copy response
|
||||
*/
|
||||
websStats.localHits++;
|
||||
#ifdef WEBS_IF_MODIFIED_SUPPORT
|
||||
if (flags & WEBS_IF_MODIFIED && !(flags & WEBS_ASP)) {
|
||||
if (sbuf.mtime <= wp->since) {
|
||||
websWrite(wp, T("HTTP/1.0 304 Use local copy\r\n"));
|
||||
|
||||
/*
|
||||
* by license terms the following line of code must
|
||||
* not be modified.
|
||||
*/
|
||||
websWrite(wp, T("Server: %s\r\n"), WEBS_NAME);
|
||||
|
||||
if (flags & WEBS_KEEP_ALIVE) {
|
||||
websWrite(wp, T("Connection: keep-alive\r\n"));
|
||||
}
|
||||
websWrite(wp, T("\r\n"));
|
||||
websSetRequestFlags(wp, flags |= WEBS_HEADER_DONE);
|
||||
websDone(wp, 304);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Output the normal HTTP response header
|
||||
*/
|
||||
if ((date = websGetDateString(NULL)) != NULL) {
|
||||
websWrite(wp, T("HTTP/1.0 200 OK\r\nDate: %s\r\n"), date);
|
||||
|
||||
/*
|
||||
* By license terms the following line of code must not be modified.
|
||||
*/
|
||||
websWrite(wp, T("Server: %s\r\n"), WEBS_NAME);
|
||||
bfree(B_L, date);
|
||||
}
|
||||
flags |= WEBS_HEADER_DONE;
|
||||
|
||||
/*
|
||||
* If this is an ASP request, ensure the remote browser doesn't cache it.
|
||||
* Send back both HTTP/1.0 and HTTP/1.1 cache control directives
|
||||
*/
|
||||
if (flags & WEBS_ASP) {
|
||||
bytes = 0;
|
||||
websWrite(wp, T("Pragma: no-cache\r\nCache-Control: no-cache\r\n"));
|
||||
|
||||
} else {
|
||||
if ((date = websGetDateString(&sbuf)) != NULL) {
|
||||
websWrite(wp, T("Last-modified: %s\r\n"), date);
|
||||
bfree(B_L, date);
|
||||
}
|
||||
bytes = sbuf.size;
|
||||
}
|
||||
|
||||
if (bytes) {
|
||||
websWrite(wp, T("Content-length: %d\r\n"), bytes);
|
||||
websSetRequestBytes(wp, bytes);
|
||||
}
|
||||
websWrite(wp, T("Content-type: %s\r\n"), websGetRequestType(wp));
|
||||
|
||||
if ((flags & WEBS_KEEP_ALIVE) && !(flags & WEBS_ASP)) {
|
||||
websWrite(wp, T("Connection: keep-alive\r\n"));
|
||||
}
|
||||
websWrite(wp, T("\r\n"));
|
||||
|
||||
/*
|
||||
* All done if the browser did a HEAD request
|
||||
*/
|
||||
if (flags & WEBS_HEAD_REQUEST) {
|
||||
websDone(wp, 200);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluate ASP requests
|
||||
*/
|
||||
if (flags & WEBS_ASP) {
|
||||
if (websAspRequest(wp, lpath) < 0) {
|
||||
return 1;
|
||||
}
|
||||
websDone(wp, 200);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef WEBS_SSL_SUPPORT
|
||||
if (wp->flags & WEBS_SECURE) {
|
||||
websDefaultWriteEvent(wp);
|
||||
} else {
|
||||
websSetRequestSocketHandler(wp, SOCKET_WRITABLE, websDefaultWriteEvent);
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* For normal web documents, return the data via background write
|
||||
*/
|
||||
websSetRequestSocketHandler(wp, SOCKET_WRITABLE, websDefaultWriteEvent);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Validate the URL path and process ".." path segments. Return -1 if the URL
|
||||
* is bad.
|
||||
*/
|
||||
|
||||
int websValidateUrl(webs_t wp, char_t *path)
|
||||
{
|
||||
char_t *parts[64]; /* Array of ptr's to URL parts */
|
||||
char_t *token, *dir, *lpath;
|
||||
int i, len, npart;
|
||||
|
||||
a_assert(websValid(wp));
|
||||
a_assert(path);
|
||||
|
||||
dir = websGetRequestDir(wp);
|
||||
if (dir == NULL || *dir == '\0') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the string so we don't destroy the original
|
||||
*/
|
||||
path = bstrdup(B_L, path);
|
||||
websDecodeUrl(path, path, gstrlen(path));
|
||||
|
||||
len = npart = 0;
|
||||
parts[0] = NULL;
|
||||
|
||||
/*
|
||||
* 22 Jul 02 -- there were reports that a directory traversal exploit was
|
||||
* possible in the WebServer running under Windows if directory paths
|
||||
* outside the server's specified root web were given by URL-encoding the
|
||||
* backslash character, like:
|
||||
*
|
||||
* GoAhead is vulnerable to a directory traversal bug. A request such as
|
||||
*
|
||||
* GoAhead-server/../../../../../../../ results in an error message
|
||||
* 'Cannot open URL'.
|
||||
|
||||
* However, by encoding the '/' character, it is possible to break out of
|
||||
* the
|
||||
* web root and read arbitrary files from the server.
|
||||
* Hence a request like:
|
||||
*
|
||||
* GoAhead-server/..%5C..%5C..%5C..%5C..%5C..%5C/winnt/win.ini returns the
|
||||
* contents of the win.ini file.
|
||||
* (Note that the description uses forward slashes (0x2F), but the example
|
||||
* uses backslashes (0x5C). In my tests, forward slashes are correctly
|
||||
* trapped, but backslashes are not. The code below substitutes forward
|
||||
* slashes for backslashes before attempting to validate that there are no
|
||||
* unauthorized paths being accessed.
|
||||
*/
|
||||
token = gstrchr(path, '\\');
|
||||
while (token != NULL)
|
||||
{
|
||||
*token = '/';
|
||||
token = gstrchr(token, '\\');
|
||||
}
|
||||
|
||||
token = gstrtok(path, T("/"));
|
||||
|
||||
/*
|
||||
* Look at each directory segment and process "." and ".." segments
|
||||
* Don't allow the browser to pop outside the root web.
|
||||
*/
|
||||
while (token != NULL) {
|
||||
if (gstrcmp(token, T("..")) == 0) {
|
||||
if (npart > 0) {
|
||||
npart--;
|
||||
}
|
||||
|
||||
} else if (gstrcmp(token, T(".")) != 0) {
|
||||
parts[npart] = token;
|
||||
len += gstrlen(token) + 1;
|
||||
npart++;
|
||||
}
|
||||
token = gstrtok(NULL, T("/"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Create local path for document. Need extra space all "/" and null.
|
||||
*/
|
||||
if (npart || (gstrcmp(path, T("/")) == 0) || (path[0] == '\0')) {
|
||||
lpath = balloc(B_L, (gstrlen(dir) + 1 + len + 1) * sizeof(char_t));
|
||||
gstrcpy(lpath, dir);
|
||||
|
||||
for (i = 0; i < npart; i++) {
|
||||
gstrcat(lpath, T("/"));
|
||||
gstrcat(lpath, parts[i]);
|
||||
}
|
||||
websSetRequestLpath(wp, lpath);
|
||||
bfree(B_L, path);
|
||||
bfree(B_L, lpath);
|
||||
|
||||
} else {
|
||||
bfree(B_L, path);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Do output back to the browser in the background. This is a socket
|
||||
* write handler.
|
||||
*/
|
||||
|
||||
static void websDefaultWriteEvent(webs_t wp)
|
||||
{
|
||||
int len, wrote, flags, bytes, written;
|
||||
char *buf;
|
||||
|
||||
a_assert(websValid(wp));
|
||||
|
||||
flags = websGetRequestFlags(wp);
|
||||
|
||||
websSetTimeMark(wp);
|
||||
|
||||
wrote = bytes = 0;
|
||||
written = websGetRequestWritten(wp);
|
||||
|
||||
/*
|
||||
* We only do this for non-ASP documents
|
||||
*/
|
||||
if ( !(flags & WEBS_ASP)) {
|
||||
bytes = websGetRequestBytes(wp);
|
||||
/*
|
||||
* Note: websWriteDataNonBlock may return less than we wanted. It will
|
||||
* return -1 on a socket error
|
||||
*/
|
||||
if ((buf = balloc(B_L, PAGE_READ_BUFSIZE)) == NULL) {
|
||||
websError(wp, 200, T("Can't get memory"));
|
||||
} else {
|
||||
while ((len = websPageReadData(wp, buf, PAGE_READ_BUFSIZE)) > 0) {
|
||||
if ((wrote = websWriteDataNonBlock(wp, buf, len)) < 0) {
|
||||
break;
|
||||
}
|
||||
written += wrote;
|
||||
if (wrote != len) {
|
||||
websPageSeek(wp, - (len - wrote));
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Safety. If we are at EOF, we must be done
|
||||
*/
|
||||
if (len == 0) {
|
||||
a_assert(written >= bytes);
|
||||
written = bytes;
|
||||
}
|
||||
bfree(B_L, buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We're done if an error, or all bytes output
|
||||
*/
|
||||
websSetRequestWritten(wp, written);
|
||||
if (wrote < 0 || written >= bytes) {
|
||||
websDone(wp, 200);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Closing down. Free resources.
|
||||
*/
|
||||
|
||||
void websDefaultClose()
|
||||
{
|
||||
if (websDefaultPage) {
|
||||
bfree(B_L, websDefaultPage);
|
||||
websDefaultPage = NULL;
|
||||
}
|
||||
if (websDefaultDir) {
|
||||
bfree(B_L, websDefaultDir);
|
||||
websDefaultDir = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Get the default page for URL requests ending in "/"
|
||||
*/
|
||||
|
||||
char_t *websGetDefaultPage()
|
||||
{
|
||||
return websDefaultPage;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Get the default web directory
|
||||
*/
|
||||
|
||||
char_t *websGetDefaultDir()
|
||||
{
|
||||
return websDefaultDir;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Set the default page for URL requests ending in "/"
|
||||
*/
|
||||
|
||||
void websSetDefaultPage(char_t *page)
|
||||
{
|
||||
a_assert(page && *page);
|
||||
|
||||
if (websDefaultPage) {
|
||||
bfree(B_L, websDefaultPage);
|
||||
}
|
||||
websDefaultPage = bstrdup(B_L, page);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Set the default web directory
|
||||
*/
|
||||
|
||||
void websSetDefaultDir(char_t *dir)
|
||||
{
|
||||
a_assert(dir && *dir);
|
||||
if (websDefaultDir) {
|
||||
bfree(B_L, websDefaultDir);
|
||||
}
|
||||
websDefaultDir = bstrdup(B_L, dir);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* ej.h -- Ejscript(TM) header
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1992-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for information on usage and redistribution
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _h_EJ
|
||||
#define _h_EJ 1
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* GoAhead Ejscript(TM) header. This defines the Ejscript API and internal
|
||||
* structures.
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#ifndef UEMF
|
||||
#include "basic/basic.h"
|
||||
#include "emf/emf.h"
|
||||
#else
|
||||
#include "uemf.h"
|
||||
#endif
|
||||
|
||||
/********************************** Defines ***********************************/
|
||||
|
||||
/******************************** Prototypes **********************************/
|
||||
|
||||
extern int ejArgs(int argc, char_t **argv, char_t *fmt, ...);
|
||||
extern void ejSetResult(int eid, char_t *s);
|
||||
extern int ejOpenEngine(sym_fd_t variables, sym_fd_t functions);
|
||||
extern void ejCloseEngine(int eid);
|
||||
extern int ejSetGlobalFunction(int eid, char_t *name,
|
||||
int (*fn)(int eid, void *handle, int argc, char_t **argv));
|
||||
extern void ejSetVar(int eid, char_t *var, char_t *value);
|
||||
extern int ejGetVar(int eid, char_t *var, char_t **value);
|
||||
extern char_t *ejEval(int eid, char_t *script, char_t **emsg);
|
||||
|
||||
#endif /* _h_EJ */
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -1,230 +0,0 @@
|
||||
/*
|
||||
* ejIntrn.h -- Ejscript(TM) header
|
||||
*
|
||||
* Copyright (c) GoAhead Software, Inc., 1992-2000
|
||||
*
|
||||
* See the file "license.txt" for information on usage and redistribution
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _h_EJINTERNAL
|
||||
#define _h_EJINTERNAL 1
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* GoAhead Ejscript(TM) header. This defines the Ejscript API and internal
|
||||
* structures.
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef CE
|
||||
#ifndef UEMF
|
||||
#include <io.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef LYNX
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef QNX4
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
#ifdef UEMF
|
||||
#include "uemf.h"
|
||||
#else
|
||||
#include <param.h>
|
||||
#include <stat.h>
|
||||
#include "basic/basicInternal.h"
|
||||
#include "emf/emfInternal.h"
|
||||
#endif
|
||||
|
||||
#include "ej.h"
|
||||
|
||||
/********************************** Defines ***********************************/
|
||||
/*
|
||||
* Constants
|
||||
*/
|
||||
#define EJ_INC 110 /* Growth for tags/tokens */
|
||||
#define EJ_SCRIPT_INC 1023 /* Growth for ej scripts */
|
||||
#define EJ_OFFSET 1 /* hAlloc doesn't like 0 entries */
|
||||
#define EJ_MAX_RECURSE 100 /* Sanity for maximum recursion */
|
||||
|
||||
/*
|
||||
* Ejscript Lexical analyser tokens
|
||||
*/
|
||||
#define TOK_ERR -1 /* Any error */
|
||||
#define TOK_LPAREN 1 /* ( */
|
||||
#define TOK_RPAREN 2 /* ) */
|
||||
#define TOK_IF 3 /* if */
|
||||
#define TOK_ELSE 4 /* else */
|
||||
#define TOK_LBRACE 5 /* { */
|
||||
#define TOK_RBRACE 6 /* } */
|
||||
#define TOK_LOGICAL 7 /* ||, &&, ! */
|
||||
#define TOK_EXPR 8 /* +, -, /, % */
|
||||
#define TOK_SEMI 9 /* ; */
|
||||
#define TOK_LITERAL 10 /* literal string */
|
||||
#define TOK_FUNCTION 11 /* function name */
|
||||
#define TOK_NEWLINE 12 /* newline white space */
|
||||
#define TOK_ID 13 /* function name */
|
||||
#define TOK_EOF 14 /* End of script */
|
||||
#define TOK_COMMA 15 /* Comma */
|
||||
#define TOK_VAR 16 /* var */
|
||||
#define TOK_ASSIGNMENT 17 /* = */
|
||||
#define TOK_FOR 18 /* for */
|
||||
#define TOK_INC_DEC 19 /* ++, -- */
|
||||
#define TOK_RETURN 20 /* return */
|
||||
|
||||
/*
|
||||
* Expression operators
|
||||
*/
|
||||
#define EXPR_LESS 1 /* < */
|
||||
#define EXPR_LESSEQ 2 /* <= */
|
||||
#define EXPR_GREATER 3 /* > */
|
||||
#define EXPR_GREATEREQ 4 /* >= */
|
||||
#define EXPR_EQ 5 /* == */
|
||||
#define EXPR_NOTEQ 6 /* != */
|
||||
#define EXPR_PLUS 7 /* + */
|
||||
#define EXPR_MINUS 8 /* - */
|
||||
#define EXPR_DIV 9 /* / */
|
||||
#define EXPR_MOD 10 /* % */
|
||||
#define EXPR_LSHIFT 11 /* << */
|
||||
#define EXPR_RSHIFT 12 /* >> */
|
||||
#define EXPR_MUL 13 /* * */
|
||||
#define EXPR_ASSIGNMENT 14 /* = */
|
||||
#define EXPR_INC 15 /* ++ */
|
||||
#define EXPR_DEC 16 /* -- */
|
||||
#define EXPR_BOOL_COMP 17 /* ! */
|
||||
/*
|
||||
* Conditional operators
|
||||
*/
|
||||
#define COND_AND 1 /* && */
|
||||
#define COND_OR 2 /* || */
|
||||
#define COND_NOT 3 /* ! */
|
||||
|
||||
/*
|
||||
* States
|
||||
*/
|
||||
#define STATE_ERR -1 /* Error state */
|
||||
#define STATE_EOF 1 /* End of file */
|
||||
#define STATE_COND 2 /* Parsing a "(conditional)" stmt */
|
||||
#define STATE_COND_DONE 3
|
||||
#define STATE_RELEXP 4 /* Parsing a relational expr */
|
||||
#define STATE_RELEXP_DONE 5
|
||||
#define STATE_EXPR 6 /* Parsing an expression */
|
||||
#define STATE_EXPR_DONE 7
|
||||
#define STATE_STMT 8 /* Parsing General statement */
|
||||
#define STATE_STMT_DONE 9
|
||||
#define STATE_STMT_BLOCK_DONE 10 /* End of block "}" */
|
||||
#define STATE_ARG_LIST 11 /* Function arg list */
|
||||
#define STATE_ARG_LIST_DONE 12
|
||||
#define STATE_DEC_LIST 16 /* Declaration list */
|
||||
#define STATE_DEC_LIST_DONE 17
|
||||
#define STATE_DEC 18
|
||||
#define STATE_DEC_DONE 19
|
||||
|
||||
#define STATE_RET 20 /* Return statement */
|
||||
|
||||
#define STATE_BEGIN STATE_STMT
|
||||
|
||||
/*
|
||||
* Flags. Used in ej_t and as parameter to parse()
|
||||
*/
|
||||
#define FLAGS_EXE 0x1 /* Execute statements */
|
||||
#define FLAGS_VARIABLES 0x2 /* Allocated variables store */
|
||||
#define FLAGS_FUNCTIONS 0x4 /* Allocated function store */
|
||||
|
||||
/*
|
||||
* Function call structure
|
||||
*/
|
||||
typedef struct {
|
||||
char_t *fname; /* Function name */
|
||||
char_t **args; /* Args for function (halloc) */
|
||||
int nArgs; /* Number of args */
|
||||
} ejfunc_t;
|
||||
|
||||
/*
|
||||
* EJ evaluation block structure
|
||||
*/
|
||||
typedef struct ejEval {
|
||||
ringq_t tokbuf; /* Current token */
|
||||
ringq_t script; /* Input script for parsing */
|
||||
char_t *putBackToken; /* Putback token string */
|
||||
int putBackTokenId; /* Putback token ID */
|
||||
char_t *line; /* Current line */
|
||||
int lineLength; /* Current line length */
|
||||
int lineNumber; /* Parse line number */
|
||||
int lineColumn; /* Column in line */
|
||||
} ejinput_t;
|
||||
|
||||
/*
|
||||
* Per Ejscript session structure
|
||||
*/
|
||||
typedef struct ej {
|
||||
ejinput_t *input; /* Input evaluation block */
|
||||
sym_fd_t functions; /* Symbol table for functions */
|
||||
sym_fd_t *variables; /* hAlloc list of variables */
|
||||
int variableMax; /* Number of entries */
|
||||
ejfunc_t *func; /* Current function */
|
||||
char_t *result; /* Current expression result */
|
||||
char_t *error; /* Error message */
|
||||
char_t *token; /* Pointer to token string */
|
||||
int tid; /* Current token id */
|
||||
int eid; /* Halloc handle */
|
||||
int flags; /* Flags */
|
||||
int userHandle; /* User defined handle */
|
||||
} ej_t;
|
||||
|
||||
/******************************** Prototypes **********************************/
|
||||
|
||||
extern int ejOpenBlock(int eid);
|
||||
extern int ejCloseBlock(int eid, int vid);
|
||||
extern char_t *ejEvalBlock(int eid, char_t *script, char_t **emsg);
|
||||
#ifndef __NO_EJ_FILE
|
||||
extern char_t *ejEvalFile(int eid, char_t *path, char_t **emsg);
|
||||
#endif
|
||||
extern int ejRemoveGlobalFunction(int eid, char_t *name);
|
||||
extern void *ejGetGlobalFunction(int eid, char_t *name);
|
||||
extern int ejSetGlobalFunctionDirect(sym_fd_t functions, char_t *name,
|
||||
int (*fn)(int eid, void *handle, int argc, char_t **argv));
|
||||
extern void ejError(ej_t* ep, char_t* fmt, ...);
|
||||
extern void ejSetUserHandle(int eid, int handle);
|
||||
extern int ejGetUserHandle(int eid);
|
||||
extern int ejGetLineNumber(int eid);
|
||||
extern char_t *ejGetResult(int eid);
|
||||
extern void ejSetLocalVar(int eid, char_t *var, char_t *value);
|
||||
extern void ejSetGlobalVar(int eid, char_t *var, char_t *value);
|
||||
|
||||
extern int ejLexOpen(ej_t* ep);
|
||||
extern void ejLexClose(ej_t* ep);
|
||||
extern int ejLexOpenScript(ej_t* ep, char_t *script);
|
||||
extern void ejLexCloseScript(ej_t* ep);
|
||||
extern void ejLexSaveInputState(ej_t* ep, ejinput_t* state);
|
||||
extern void ejLexFreeInputState(ej_t* ep, ejinput_t* state);
|
||||
extern void ejLexRestoreInputState(ej_t* ep, ejinput_t* state);
|
||||
extern int ejLexGetToken(ej_t* ep, int state);
|
||||
extern void ejLexPutbackToken(ej_t* ep, int tid, char_t *string);
|
||||
|
||||
extern sym_fd_t ejGetVariableTable(int eid);
|
||||
extern sym_fd_t ejGetFunctionTable(int eid);
|
||||
|
||||
extern int ejEmfOpen(int eid);
|
||||
extern void ejEmfClose(int eid);
|
||||
|
||||
extern int ejEmfDbRead(int eid, void *handle, int argc, char_t **argv);
|
||||
extern int ejEmfDbReadKeyed(int eid, void *handle, int argc, char_t **argv);
|
||||
extern int ejEmfDbTableGetNrow(int eid, void *handle, int argc, char_t **argv);
|
||||
extern int ejEmfDbDeleteRow(int eid, void *handle, int argc, char_t **argv);
|
||||
extern int ejEmfTrace(int eid, void *handle, int argc, char_t **argv);
|
||||
extern int ejEmfDbWrite(int eid, void *handle, int argc, char_t **argv);
|
||||
extern int ejEmfDbCollectTable(int eid, void *handle, int argc, char_t **argv);
|
||||
|
||||
#endif /* _h_EJINTERNAL */
|
||||
@@ -1,721 +0,0 @@
|
||||
/*
|
||||
* ejlex.c -- Ejscript(TM) Lexical Analyser
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* Ejscript lexical analyser. This implementes a lexical analyser for a
|
||||
* a subset of the JavaScript language.
|
||||
*/
|
||||
|
||||
/********************************** Includes **********************************/
|
||||
|
||||
#include "ejIntrn.h"
|
||||
|
||||
#ifdef UEMF
|
||||
#include "uemf.h"
|
||||
#else
|
||||
#include "basic/basicInternal.h"
|
||||
#endif
|
||||
|
||||
/********************************** Defines ***********************************/
|
||||
#define OCTAL 8
|
||||
#define HEX 16
|
||||
/****************************** Forward Declarations **************************/
|
||||
|
||||
static int getLexicalToken(ej_t* ep, int state);
|
||||
static int tokenAddChar(ej_t *ep, int c);
|
||||
static int inputGetc(ej_t* ep);
|
||||
static void inputPutback(ej_t* ep, int c);
|
||||
static int charConvert(ej_t* ep, int base, int maxDig);
|
||||
|
||||
/************************************* Code ***********************************/
|
||||
/*
|
||||
* Setup the lexical analyser
|
||||
*/
|
||||
|
||||
int ejLexOpen(ej_t* ep)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Close the lexicial analyser
|
||||
*/
|
||||
|
||||
void ejLexClose(ej_t* ep)
|
||||
{
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Open a new input script
|
||||
*/
|
||||
|
||||
int ejLexOpenScript(ej_t* ep, char_t *script)
|
||||
{
|
||||
ejinput_t *ip;
|
||||
|
||||
a_assert(ep);
|
||||
a_assert(script);
|
||||
|
||||
if ((ep->input = balloc(B_L, sizeof(ejinput_t))) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
ip = ep->input;
|
||||
memset(ip, 0, sizeof(*ip));
|
||||
|
||||
a_assert(ip);
|
||||
a_assert(ip->putBackToken == NULL);
|
||||
a_assert(ip->putBackTokenId == 0);
|
||||
|
||||
/*
|
||||
* Create the parse token buffer and script buffer
|
||||
*/
|
||||
if (ringqOpen(&ip->tokbuf, EJ_INC, -1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (ringqOpen(&ip->script, EJ_SCRIPT_INC, -1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* Put the Ejscript into a ring queue for easy parsing
|
||||
*/
|
||||
ringqPutStr(&ip->script, script);
|
||||
|
||||
ip->lineNumber = 1;
|
||||
ip->lineLength = 0;
|
||||
ip->lineColumn = 0;
|
||||
ip->line = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Close the input script
|
||||
*/
|
||||
|
||||
void ejLexCloseScript(ej_t* ep)
|
||||
{
|
||||
ejinput_t *ip;
|
||||
|
||||
a_assert(ep);
|
||||
|
||||
ip = ep->input;
|
||||
a_assert(ip);
|
||||
|
||||
if (ip->putBackToken) {
|
||||
bfree(B_L, ip->putBackToken);
|
||||
ip->putBackToken = NULL;
|
||||
}
|
||||
ip->putBackTokenId = 0;
|
||||
|
||||
if (ip->line) {
|
||||
bfree(B_L, ip->line);
|
||||
ip->line = NULL;
|
||||
}
|
||||
|
||||
ringqClose(&ip->tokbuf);
|
||||
ringqClose(&ip->script);
|
||||
|
||||
bfree(B_L, ip);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Save the input state
|
||||
*/
|
||||
|
||||
void ejLexSaveInputState(ej_t* ep, ejinput_t* state)
|
||||
{
|
||||
ejinput_t *ip;
|
||||
|
||||
a_assert(ep);
|
||||
|
||||
ip = ep->input;
|
||||
a_assert(ip);
|
||||
|
||||
*state = *ip;
|
||||
if (ip->putBackToken) {
|
||||
state->putBackToken = bstrdup(B_L, ip->putBackToken);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Restore the input state
|
||||
*/
|
||||
|
||||
void ejLexRestoreInputState(ej_t* ep, ejinput_t* state)
|
||||
{
|
||||
ejinput_t *ip;
|
||||
|
||||
a_assert(ep);
|
||||
|
||||
ip = ep->input;
|
||||
a_assert(ip);
|
||||
|
||||
ip->tokbuf = state->tokbuf;
|
||||
ip->script = state->script;
|
||||
ip->putBackTokenId = state->putBackTokenId;
|
||||
if (ip->putBackToken) {
|
||||
bfree(B_L, ip->putBackToken);
|
||||
}
|
||||
if (state->putBackToken) {
|
||||
ip->putBackToken = bstrdup(B_L, state->putBackToken);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Free a saved input state
|
||||
*/
|
||||
|
||||
void ejLexFreeInputState(ej_t* ep, ejinput_t* state)
|
||||
{
|
||||
if (state->putBackToken) {
|
||||
bfree(B_L, state->putBackToken);
|
||||
state->putBackToken = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Get the next Ejscript token
|
||||
*/
|
||||
|
||||
int ejLexGetToken(ej_t* ep, int state)
|
||||
{
|
||||
ep->tid = getLexicalToken(ep, state);
|
||||
/*
|
||||
* commented out 04 Apr 02 Bg Porter -- we found a case where very long
|
||||
* arguments to write() were being corrupted downstream in the trace call
|
||||
* (the ep->token pointer was being overwritten with the trace message.
|
||||
* restore this if it's useful for your debugging.
|
||||
trace(9, T("ejGetToken: %d, \"%s\"\n"), ep->tid, ep->token);
|
||||
*/
|
||||
return ep->tid;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Get the next Ejscript token
|
||||
*/
|
||||
|
||||
static int getLexicalToken(ej_t* ep, int state)
|
||||
{
|
||||
ringq_t *inq, *tokq;
|
||||
ejinput_t* ip;
|
||||
int done, tid, c, quote, style;
|
||||
|
||||
a_assert(ep);
|
||||
ip = ep->input;
|
||||
a_assert(ip);
|
||||
|
||||
inq = &ip->script;
|
||||
tokq = &ip->tokbuf;
|
||||
|
||||
ep->tid = -1;
|
||||
tid = -1;
|
||||
ep->token = T("");
|
||||
|
||||
ringqFlush(tokq);
|
||||
|
||||
if (ip->putBackTokenId > 0) {
|
||||
ringqPutStr(tokq, ip->putBackToken);
|
||||
tid = ip->putBackTokenId;
|
||||
ip->putBackTokenId = 0;
|
||||
ep->token = (char_t*) tokq->servp;
|
||||
return tid;
|
||||
}
|
||||
|
||||
if ((c = inputGetc(ep)) < 0) {
|
||||
return TOK_EOF;
|
||||
}
|
||||
|
||||
for (done = 0; !done; ) {
|
||||
switch (c) {
|
||||
case -1:
|
||||
return TOK_EOF;
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
do {
|
||||
if ((c = inputGetc(ep)) < 0)
|
||||
break;
|
||||
} while (c == ' ' || c == '\t' || c == '\r');
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
return TOK_NEWLINE;
|
||||
|
||||
case '(':
|
||||
tokenAddChar(ep, c);
|
||||
return TOK_LPAREN;
|
||||
|
||||
case ')':
|
||||
tokenAddChar(ep, c);
|
||||
return TOK_RPAREN;
|
||||
|
||||
case '{':
|
||||
tokenAddChar(ep, c);
|
||||
return TOK_LBRACE;
|
||||
|
||||
case '}':
|
||||
tokenAddChar(ep, c);
|
||||
return TOK_RBRACE;
|
||||
|
||||
case '+':
|
||||
if ((c = inputGetc(ep)) < 0) {
|
||||
ejError(ep, T("Syntax Error"));
|
||||
return TOK_ERR;
|
||||
}
|
||||
if (c != '+' ) {
|
||||
inputPutback(ep, c);
|
||||
tokenAddChar(ep, EXPR_PLUS);
|
||||
return TOK_EXPR;
|
||||
}
|
||||
tokenAddChar(ep, EXPR_INC);
|
||||
return TOK_INC_DEC;
|
||||
|
||||
case '-':
|
||||
if ((c = inputGetc(ep)) < 0) {
|
||||
ejError(ep, T("Syntax Error"));
|
||||
return TOK_ERR;
|
||||
}
|
||||
if (c != '-' ) {
|
||||
inputPutback(ep, c);
|
||||
tokenAddChar(ep, EXPR_MINUS);
|
||||
return TOK_EXPR;
|
||||
}
|
||||
tokenAddChar(ep, EXPR_DEC);
|
||||
return TOK_INC_DEC;
|
||||
|
||||
case '*':
|
||||
tokenAddChar(ep, EXPR_MUL);
|
||||
return TOK_EXPR;
|
||||
|
||||
case '%':
|
||||
tokenAddChar(ep, EXPR_MOD);
|
||||
return TOK_EXPR;
|
||||
|
||||
case '/':
|
||||
/*
|
||||
* Handle the division operator and comments
|
||||
*/
|
||||
if ((c = inputGetc(ep)) < 0) {
|
||||
ejError(ep, T("Syntax Error"));
|
||||
return TOK_ERR;
|
||||
}
|
||||
if (c != '*' && c != '/') {
|
||||
inputPutback(ep, c);
|
||||
tokenAddChar(ep, EXPR_DIV);
|
||||
return TOK_EXPR;
|
||||
}
|
||||
style = c;
|
||||
/*
|
||||
* Eat comments. Both C and C++ comment styles are supported.
|
||||
*/
|
||||
while (1) {
|
||||
if ((c = inputGetc(ep)) < 0) {
|
||||
ejError(ep, T("Syntax Error"));
|
||||
return TOK_ERR;
|
||||
}
|
||||
if (c == '\n' && style == '/') {
|
||||
break;
|
||||
} else if (c == '*') {
|
||||
c = inputGetc(ep);
|
||||
if (style == '/') {
|
||||
if (c == '\n') {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (c == '/') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Continue looking for a token, so get the next character
|
||||
*/
|
||||
if ((c = inputGetc(ep)) < 0) {
|
||||
return TOK_EOF;
|
||||
}
|
||||
break;
|
||||
|
||||
case '<': /* < and <= */
|
||||
if ((c = inputGetc(ep)) < 0) {
|
||||
ejError(ep, T("Syntax Error"));
|
||||
return TOK_ERR;
|
||||
}
|
||||
if (c == '<') {
|
||||
tokenAddChar(ep, EXPR_LSHIFT);
|
||||
return TOK_EXPR;
|
||||
} else if (c == '=') {
|
||||
tokenAddChar(ep, EXPR_LESSEQ);
|
||||
return TOK_EXPR;
|
||||
}
|
||||
tokenAddChar(ep, EXPR_LESS);
|
||||
inputPutback(ep, c);
|
||||
return TOK_EXPR;
|
||||
|
||||
case '>': /* > and >= */
|
||||
if ((c = inputGetc(ep)) < 0) {
|
||||
ejError(ep, T("Syntax Error"));
|
||||
return TOK_ERR;
|
||||
}
|
||||
if (c == '>') {
|
||||
tokenAddChar(ep, EXPR_RSHIFT);
|
||||
return TOK_EXPR;
|
||||
} else if (c == '=') {
|
||||
tokenAddChar(ep, EXPR_GREATEREQ);
|
||||
return TOK_EXPR;
|
||||
}
|
||||
tokenAddChar(ep, EXPR_GREATER);
|
||||
inputPutback(ep, c);
|
||||
return TOK_EXPR;
|
||||
|
||||
case '=': /* "==" */
|
||||
if ((c = inputGetc(ep)) < 0) {
|
||||
ejError(ep, T("Syntax Error"));
|
||||
return TOK_ERR;
|
||||
}
|
||||
if (c == '=') {
|
||||
tokenAddChar(ep, EXPR_EQ);
|
||||
return TOK_EXPR;
|
||||
}
|
||||
inputPutback(ep, c);
|
||||
return TOK_ASSIGNMENT;
|
||||
|
||||
case '!': /* "!=" or "!"*/
|
||||
if ((c = inputGetc(ep)) < 0) {
|
||||
ejError(ep, T("Syntax Error"));
|
||||
return TOK_ERR;
|
||||
}
|
||||
if (c == '=') {
|
||||
tokenAddChar(ep, EXPR_NOTEQ);
|
||||
return TOK_EXPR;
|
||||
}
|
||||
inputPutback(ep, c);
|
||||
tokenAddChar(ep, EXPR_BOOL_COMP);
|
||||
return TOK_EXPR;
|
||||
|
||||
case ';':
|
||||
tokenAddChar(ep, c);
|
||||
return TOK_SEMI;
|
||||
|
||||
case ',':
|
||||
tokenAddChar(ep, c);
|
||||
return TOK_COMMA;
|
||||
|
||||
case '|': /* "||" */
|
||||
if ((c = inputGetc(ep)) < 0 || c != '|') {
|
||||
ejError(ep, T("Syntax Error"));
|
||||
return TOK_ERR;
|
||||
}
|
||||
tokenAddChar(ep, COND_OR);
|
||||
return TOK_LOGICAL;
|
||||
|
||||
case '&': /* "&&" */
|
||||
if ((c = inputGetc(ep)) < 0 || c != '&') {
|
||||
ejError(ep, T("Syntax Error"));
|
||||
return TOK_ERR;
|
||||
}
|
||||
tokenAddChar(ep, COND_AND);
|
||||
return TOK_LOGICAL;
|
||||
|
||||
case '\"': /* String quote */
|
||||
case '\'':
|
||||
quote = c;
|
||||
if ((c = inputGetc(ep)) < 0) {
|
||||
ejError(ep, T("Syntax Error"));
|
||||
return TOK_ERR;
|
||||
}
|
||||
|
||||
while (c != quote) {
|
||||
/*
|
||||
* check for escape sequence characters
|
||||
*/
|
||||
if (c == '\\') {
|
||||
c = inputGetc(ep);
|
||||
|
||||
if (gisdigit(c)) {
|
||||
/*
|
||||
* octal support, \101 maps to 65 = 'A'. put first char
|
||||
* back so converter will work properly.
|
||||
*/
|
||||
inputPutback(ep, c);
|
||||
c = charConvert(ep, OCTAL, 3);
|
||||
|
||||
} else {
|
||||
switch (c) {
|
||||
case 'n':
|
||||
c = '\n'; break;
|
||||
case 'b':
|
||||
c = '\b'; break;
|
||||
case 'f':
|
||||
c = '\f'; break;
|
||||
case 'r':
|
||||
c = '\r'; break;
|
||||
case 't':
|
||||
c = '\t'; break;
|
||||
case 'x':
|
||||
/*
|
||||
* hex support, \x41 maps to 65 = 'A'
|
||||
*/
|
||||
c = charConvert(ep, HEX, 2);
|
||||
break;
|
||||
case 'u':
|
||||
/*
|
||||
* unicode support, \x0401 maps to 65 = 'A'
|
||||
*/
|
||||
c = charConvert(ep, HEX, 2);
|
||||
c = c*16 + charConvert(ep, HEX, 2);
|
||||
|
||||
break;
|
||||
case '\'':
|
||||
case '\"':
|
||||
case '\\':
|
||||
break;
|
||||
default:
|
||||
ejError(ep, T("Invalid Escape Sequence"));
|
||||
return TOK_ERR;
|
||||
}
|
||||
}
|
||||
if (tokenAddChar(ep, c) < 0) {
|
||||
return TOK_ERR;
|
||||
}
|
||||
} else {
|
||||
if (tokenAddChar(ep, c) < 0) {
|
||||
return TOK_ERR;
|
||||
}
|
||||
}
|
||||
if ((c = inputGetc(ep)) < 0) {
|
||||
ejError(ep, T("Unmatched Quote"));
|
||||
return TOK_ERR;
|
||||
}
|
||||
}
|
||||
return TOK_LITERAL;
|
||||
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
do {
|
||||
if (tokenAddChar(ep, c) < 0) {
|
||||
return TOK_ERR;
|
||||
}
|
||||
if ((c = inputGetc(ep)) < 0)
|
||||
break;
|
||||
} while (gisdigit(c));
|
||||
inputPutback(ep, c);
|
||||
return TOK_LITERAL;
|
||||
|
||||
default:
|
||||
/*
|
||||
* Identifiers or a function names
|
||||
*/
|
||||
while (1) {
|
||||
if (c == '\\') {
|
||||
/*
|
||||
* just ignore any \ characters.
|
||||
*/
|
||||
} else if (tokenAddChar(ep, c) < 0) {
|
||||
break;
|
||||
}
|
||||
if ((c = inputGetc(ep)) < 0) {
|
||||
break;
|
||||
}
|
||||
if (!gisalnum(c) && c != '$' && c != '_' &&
|
||||
c != '\\') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (! gisalpha(*tokq->servp) && *tokq->servp != '$' &&
|
||||
*tokq->servp != '_') {
|
||||
ejError(ep, T("Invalid identifier %s"), tokq->servp);
|
||||
return TOK_ERR;
|
||||
}
|
||||
/*
|
||||
* Check for reserved words (only "if", "else", "var", "for"
|
||||
* and "return" at the moment)
|
||||
*/
|
||||
if (state == STATE_STMT) {
|
||||
if (gstrcmp(ep->token, T("if")) == 0) {
|
||||
return TOK_IF;
|
||||
} else if (gstrcmp(ep->token, T("else")) == 0) {
|
||||
return TOK_ELSE;
|
||||
} else if (gstrcmp(ep->token, T("var")) == 0) {
|
||||
return TOK_VAR;
|
||||
} else if (gstrcmp(ep->token, T("for")) == 0) {
|
||||
return TOK_FOR;
|
||||
} else if (gstrcmp(ep->token, T("return")) == 0) {
|
||||
if ((c == ';') || (c == '(')) {
|
||||
inputPutback(ep, c);
|
||||
}
|
||||
return TOK_RETURN;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip white space after token to find out whether this is
|
||||
* a function or not.
|
||||
*/
|
||||
while (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
|
||||
if ((c = inputGetc(ep)) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
tid = (c == '(') ? TOK_FUNCTION : TOK_ID;
|
||||
done++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Putback the last extra character for next time
|
||||
*/
|
||||
inputPutback(ep, c);
|
||||
return tid;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Putback the last token read
|
||||
*/
|
||||
|
||||
void ejLexPutbackToken(ej_t* ep, int tid, char_t *string)
|
||||
{
|
||||
ejinput_t* ip;
|
||||
|
||||
a_assert(ep);
|
||||
ip = ep->input;
|
||||
a_assert(ip);
|
||||
|
||||
if (ip->putBackToken) {
|
||||
bfree(B_L, ip->putBackToken);
|
||||
}
|
||||
ip->putBackTokenId = tid;
|
||||
ip->putBackToken = bstrdup(B_L, string);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Add a character to the token ringq buffer
|
||||
*/
|
||||
|
||||
static int tokenAddChar(ej_t *ep, int c)
|
||||
{
|
||||
ejinput_t* ip;
|
||||
|
||||
a_assert(ep);
|
||||
ip = ep->input;
|
||||
a_assert(ip);
|
||||
|
||||
if (ringqPutc(&ip->tokbuf, (char_t) c) < 0) {
|
||||
ejError(ep, T("Token too big"));
|
||||
return -1;
|
||||
}
|
||||
* ((char_t*) ip->tokbuf.endp) = '\0';
|
||||
ep->token = (char_t*) ip->tokbuf.servp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Get another input character
|
||||
*/
|
||||
|
||||
static int inputGetc(ej_t* ep)
|
||||
{
|
||||
ejinput_t *ip;
|
||||
int c, len;
|
||||
|
||||
a_assert(ep);
|
||||
ip = ep->input;
|
||||
|
||||
if ((len = ringqLen(&ip->script)) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
c = ringqGetc(&ip->script);
|
||||
|
||||
if (c == '\n') {
|
||||
ip->lineNumber++;
|
||||
ip->lineColumn = 0;
|
||||
} else {
|
||||
if ((ip->lineColumn + 2) >= ip->lineLength) {
|
||||
ip->lineLength += EJ_INC;
|
||||
ip->line = brealloc(B_L, ip->line, ip->lineLength * sizeof(char_t));
|
||||
}
|
||||
ip->line[ip->lineColumn++] = c;
|
||||
ip->line[ip->lineColumn] = '\0';
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Putback a character onto the input queue
|
||||
*/
|
||||
|
||||
static void inputPutback(ej_t* ep, int c)
|
||||
{
|
||||
ejinput_t *ip;
|
||||
|
||||
a_assert(ep);
|
||||
|
||||
ip = ep->input;
|
||||
ringqInsertc(&ip->script, (char_t) c);
|
||||
ip->lineColumn--;
|
||||
ip->line[ip->lineColumn] = '\0';
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Convert a hex or octal character back to binary, return original char if
|
||||
* not a hex digit
|
||||
*/
|
||||
|
||||
static int charConvert(ej_t* ep, int base, int maxDig)
|
||||
{
|
||||
int i, c, lval, convChar;
|
||||
|
||||
lval = 0;
|
||||
for (i = 0; i < maxDig; i++) {
|
||||
if ((c = inputGetc(ep)) < 0) {
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Initialize to out of range value
|
||||
*/
|
||||
convChar = base;
|
||||
if (gisdigit(c)) {
|
||||
convChar = c - '0';
|
||||
} else if (c >= 'a' && c <= 'f') {
|
||||
convChar = c - 'a' + 10;
|
||||
} else if (c >= 'A' && c <= 'F') {
|
||||
convChar = c - 'A' + 10;
|
||||
}
|
||||
/*
|
||||
* if unexpected character then return it to buffer.
|
||||
*/
|
||||
if (convChar >= base) {
|
||||
inputPutback(ep, c);
|
||||
break;
|
||||
}
|
||||
lval = (lval * base) + convChar;
|
||||
}
|
||||
return lval;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* emfdb.h -- EMF database compatability functions for GoAhead WebServer.
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
/*
|
||||
* Emf-like textfile database support for WebServer 2.1.
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#ifndef _h_EMFDB
|
||||
#define _h_EMFDB 1
|
||||
|
||||
#ifndef UEMF
|
||||
#include "basic/basic.h"
|
||||
#include "emf/emf.h"
|
||||
#else
|
||||
#include "uemf.h"
|
||||
#endif
|
||||
|
||||
|
||||
/********************************* Defines ************************************/
|
||||
|
||||
#define T_INT 0
|
||||
#define T_STRING 1
|
||||
|
||||
#define DB_OK 0
|
||||
#define DB_ERR_GENERAL -1
|
||||
#define DB_ERR_COL_NOT_FOUND -2
|
||||
#define DB_ERR_COL_DELETED -3
|
||||
#define DB_ERR_ROW_NOT_FOUND -4
|
||||
#define DB_ERR_ROW_DELETED -5
|
||||
#define DB_ERR_TABLE_NOT_FOUND -6
|
||||
#define DB_ERR_TABLE_DELETED -7
|
||||
#define DB_ERR_BAD_FORMAT -8
|
||||
|
||||
typedef struct dbTable_s {
|
||||
char_t *name;
|
||||
int nColumns;
|
||||
char_t **columnNames;
|
||||
int *columnTypes;
|
||||
int nRows;
|
||||
int **rows;
|
||||
} dbTable_t;
|
||||
|
||||
/********************************** Prototypes ********************************/
|
||||
|
||||
/*
|
||||
* Add a schema to the module-internal schema database
|
||||
*/
|
||||
extern int dbRegisterDBSchema(dbTable_t *sTable);
|
||||
|
||||
extern int dbOpen(char_t *databasename, char_t *filename,
|
||||
int (*gettime)(int did), int flags);
|
||||
extern void dbClose(int did);
|
||||
extern int dbGetTableId(int did, char_t *tname);
|
||||
extern char_t *dbGetTableName(int did, int tid);
|
||||
extern int dbReadInt(int did, char_t *table, char_t *column, int row,
|
||||
int *returnValue);
|
||||
extern int dbReadStr(int did, char_t *table, char_t *column, int row,
|
||||
char_t **returnValue);
|
||||
extern int dbWriteInt(int did, char_t *table, char_t *column, int row,
|
||||
int idata);
|
||||
extern int dbWriteStr(int did, char_t *table, char_t *column, int row,
|
||||
char_t *s);
|
||||
extern int dbAddRow(int did, char_t *table);
|
||||
extern int dbDeleteRow(int did, char_t *table, int rid);
|
||||
extern int dbSetTableNrow(int did, char_t *table, int nNewRows);
|
||||
extern int dbGetTableNrow(int did, char_t *table);
|
||||
|
||||
/*
|
||||
* Dump the contents of a database to file
|
||||
*/
|
||||
extern int dbSave(int did, char_t *filename, int flags);
|
||||
|
||||
/*
|
||||
* Load the contents of a database to file
|
||||
*/
|
||||
extern int dbLoad(int did, char_t *filename, int flags);
|
||||
|
||||
/*
|
||||
* Search for a data in a given column
|
||||
*/
|
||||
extern int dbSearchStr(int did, char_t *table, char_t *column,
|
||||
char_t *value, int flags);
|
||||
|
||||
extern void dbZero(int did);
|
||||
|
||||
extern char_t *basicGetProductDir();
|
||||
extern void basicSetProductDir(char_t *proddir);
|
||||
|
||||
#endif /* _h_EMFDB */
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* form.c -- Form processing (in-memory CGI) for the GoAhead Web server
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/********************************** Description *******************************/
|
||||
|
||||
/*
|
||||
* This module implements the /goform handler. It emulates CGI processing
|
||||
* but performs this in-process and not as an external process. This enables
|
||||
* a very high performance implementation with easy parsing and decoding
|
||||
* of query strings and posted data.
|
||||
*/
|
||||
|
||||
/*********************************** Includes *********************************/
|
||||
|
||||
#include "wsIntrn.h"
|
||||
|
||||
/************************************ Locals **********************************/
|
||||
|
||||
static sym_fd_t formSymtab = -1; /* Symbol table for form handlers */
|
||||
|
||||
/************************************* Code ***********************************/
|
||||
/*
|
||||
* Process a form request. Returns 1 always to indicate it handled the URL
|
||||
*/
|
||||
|
||||
int websFormHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg,
|
||||
char_t *url, char_t *path, char_t *query)
|
||||
{
|
||||
sym_t *sp;
|
||||
char_t formBuf[FNAMESIZE];
|
||||
char_t *cp, *formName;
|
||||
int (*fn)(void *sock, char_t *path, char_t *args);
|
||||
|
||||
a_assert(websValid(wp));
|
||||
a_assert(url && *url);
|
||||
a_assert(path && *path == '/');
|
||||
|
||||
websStats.formHits++;
|
||||
|
||||
/*
|
||||
* Extract the form name
|
||||
*/
|
||||
gstrncpy(formBuf, path, TSZ(formBuf));
|
||||
if ((formName = gstrchr(&formBuf[1], '/')) == NULL) {
|
||||
websError(wp, 200, T("Missing form name"));
|
||||
return 1;
|
||||
}
|
||||
formName++;
|
||||
if ((cp = gstrchr(formName, '/')) != NULL) {
|
||||
*cp = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup the C form function first and then try tcl (no javascript support
|
||||
* yet).
|
||||
*/
|
||||
sp = symLookup(formSymtab, formName);
|
||||
if (sp == NULL) {
|
||||
websError(wp, 200, T("Form %s is not defined"), formName);
|
||||
} else {
|
||||
fn = (int (*)(void *, char_t *, char_t *)) sp->content.value.integer;
|
||||
a_assert(fn);
|
||||
if (fn) {
|
||||
/*
|
||||
* For good practice, forms must call websDone()
|
||||
*/
|
||||
(*fn)((void*) wp, formName, query);
|
||||
|
||||
/*
|
||||
* Remove the test to force websDone, since this prevents
|
||||
* the server "push" from a form>
|
||||
*/
|
||||
#if 0 /* push */
|
||||
if (websValid(wp)) {
|
||||
websError(wp, 200, T("Form didn't call websDone"));
|
||||
}
|
||||
#endif /* push */
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Define a form function in the "form" map space.
|
||||
*/
|
||||
|
||||
int websFormDefine(char_t *name, void (*fn)(webs_t wp, char_t *path,
|
||||
char_t *query))
|
||||
{
|
||||
a_assert(name && *name);
|
||||
a_assert(fn);
|
||||
|
||||
if (fn == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
symEnter(formSymtab, name, valueInteger((int) fn), (int) NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Open the symbol table for forms.
|
||||
*/
|
||||
|
||||
void websFormOpen()
|
||||
{
|
||||
formSymtab = symOpen(WEBS_SYM_INIT);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Close the symbol table for forms.
|
||||
*/
|
||||
|
||||
void websFormClose()
|
||||
{
|
||||
if (formSymtab != -1) {
|
||||
symClose(formSymtab);
|
||||
formSymtab = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Write a webs header. This is a convenience routine to write a common
|
||||
* header for a form back to the browser.
|
||||
*/
|
||||
|
||||
void websHeader(webs_t wp)
|
||||
{
|
||||
a_assert(websValid(wp));
|
||||
|
||||
websWrite(wp, T("HTTP/1.0 200 OK\n"));
|
||||
|
||||
/*
|
||||
* By license terms the following line of code must not be modified
|
||||
*/
|
||||
websWrite(wp, T("Server: %s\r\n"), WEBS_NAME);
|
||||
|
||||
websWrite(wp, T("Pragma: no-cache\n"));
|
||||
websWrite(wp, T("Cache-control: no-cache\n"));
|
||||
websWrite(wp, T("Content-Type: text/html\n"));
|
||||
websWrite(wp, T("\n"));
|
||||
websWrite(wp, T("<html>\n"));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Write a webs footer
|
||||
*/
|
||||
|
||||
void websFooter(webs_t wp)
|
||||
{
|
||||
a_assert(websValid(wp));
|
||||
|
||||
websWrite(wp, T("</html>\n"));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,194 +0,0 @@
|
||||
/*
|
||||
* h.c -- Handle allocation module
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* This module provides a simple API to allocate and free handles
|
||||
* It maintains a dynamic array of pointers. These usually point to
|
||||
* per-handle structures.
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#ifdef UEMF
|
||||
#include "uemf.h"
|
||||
#else
|
||||
#include "basic/basicInternal.h"
|
||||
#endif
|
||||
|
||||
/********************************** Defines ***********************************/
|
||||
/*
|
||||
* The handle list stores the length of the list and the number of used
|
||||
* handles in the first two words. These are hidden from the caller by
|
||||
* returning a pointer to the third word to the caller
|
||||
*/
|
||||
|
||||
#define H_LEN 0 /* First entry holds length of list */
|
||||
#define H_USED 1 /* Second entry holds number of used */
|
||||
#define H_OFFSET 2 /* Offset to real start of list */
|
||||
|
||||
#define H_INCR 16 /* Grow handle list in chunks this size */
|
||||
|
||||
/*********************************** Code *************************************/
|
||||
/*
|
||||
* Allocate a new file handle. On the first call, the caller must set the
|
||||
* handle map to be a pointer to a null pointer. *map points to the second
|
||||
* element in the handle array.
|
||||
*/
|
||||
|
||||
#ifdef B_STATS
|
||||
int HALLOC(B_ARGS_DEC, void ***map)
|
||||
#else
|
||||
int hAlloc(void ***map)
|
||||
#endif
|
||||
{
|
||||
int *mp;
|
||||
int handle, len, memsize, incr;
|
||||
|
||||
a_assert(map);
|
||||
|
||||
if (*map == NULL) {
|
||||
incr = H_INCR;
|
||||
memsize = (incr + H_OFFSET) * sizeof(void**);
|
||||
#ifdef B_STATS
|
||||
if ((mp = (int*) balloc(B_ARGS, memsize)) == NULL) {
|
||||
#else
|
||||
if ((mp = (int*) balloc(B_L, memsize)) == NULL) {
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
memset(mp, 0, memsize);
|
||||
mp[H_LEN] = incr;
|
||||
mp[H_USED] = 0;
|
||||
*map = (void**) &mp[H_OFFSET];
|
||||
} else {
|
||||
mp = &((*(int**)map)[-H_OFFSET]);
|
||||
}
|
||||
|
||||
len = mp[H_LEN];
|
||||
|
||||
/*
|
||||
* Find the first null handle
|
||||
*/
|
||||
if (mp[H_USED] < mp[H_LEN]) {
|
||||
for (handle = 0; handle < len; handle++) {
|
||||
if (mp[handle+H_OFFSET] == 0) {
|
||||
mp[H_USED]++;
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
handle = len;
|
||||
}
|
||||
|
||||
/*
|
||||
* No free handle so grow the handle list. Grow list in chunks of H_INCR.
|
||||
*/
|
||||
len += H_INCR;
|
||||
memsize = (len + H_OFFSET) * sizeof(void**);
|
||||
if ((mp = (int*) brealloc(B_L, (void*) mp, memsize)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
*map = (void**) &mp[H_OFFSET];
|
||||
mp[H_LEN] = len;
|
||||
memset(&mp[H_OFFSET + len - H_INCR], 0, sizeof(int*) * H_INCR);
|
||||
mp[H_USED]++;
|
||||
return handle;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Free a handle. This function returns the value of the largest
|
||||
* handle in use plus 1, to be saved as a max value.
|
||||
*/
|
||||
|
||||
int hFree(void ***map, int handle)
|
||||
{
|
||||
int *mp;
|
||||
int len;
|
||||
|
||||
a_assert(map);
|
||||
mp = &((*(int**)map)[-H_OFFSET]);
|
||||
a_assert(mp[H_LEN] >= H_INCR);
|
||||
|
||||
a_assert(mp[handle + H_OFFSET]);
|
||||
a_assert(mp[H_USED]);
|
||||
mp[handle + H_OFFSET] = 0;
|
||||
if (--(mp[H_USED]) == 0) {
|
||||
bfree(B_L, (void*) mp);
|
||||
*map = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the greatest handle number in use.
|
||||
*/
|
||||
if (*map == NULL) {
|
||||
handle = -1;
|
||||
} else {
|
||||
len = mp[H_LEN];
|
||||
if (mp[H_USED] < mp[H_LEN]) {
|
||||
for (handle = len - 1; handle >= 0; handle--) {
|
||||
if (mp[handle + H_OFFSET])
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
handle = len;
|
||||
}
|
||||
}
|
||||
return handle + 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Allocate an entry in the halloc array.
|
||||
*/
|
||||
|
||||
#ifdef B_STATS
|
||||
int HALLOCENTRY(B_ARGS_DEC, void ***list, int *max, int size)
|
||||
#else
|
||||
int hAllocEntry(void ***list, int *max, int size)
|
||||
#endif
|
||||
{
|
||||
char_t *cp;
|
||||
int id;
|
||||
|
||||
a_assert(list);
|
||||
a_assert(max);
|
||||
|
||||
#ifdef B_STATS
|
||||
if ((id = HALLOC(B_ARGS, (void***) list)) < 0) {
|
||||
#else
|
||||
if ((id = hAlloc((void***) list)) < 0) {
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
#ifdef B_STATS
|
||||
if ((cp = balloc(B_ARGS, size)) == NULL) {
|
||||
#else
|
||||
if ((cp = balloc(B_L, size)) == NULL) {
|
||||
#endif
|
||||
hFree(list, id);
|
||||
return -1;
|
||||
}
|
||||
a_assert(cp);
|
||||
memset(cp, 0, size);
|
||||
|
||||
(*list)[id] = (void*) cp;
|
||||
}
|
||||
|
||||
if (id >= *max) {
|
||||
*max = id + 1;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,411 +0,0 @@
|
||||
/*
|
||||
* handler.c -- URL handler support
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* This module implements a URL handler interface and API to permit
|
||||
* the addition of user definable URL processors.
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#include "wsIntrn.h"
|
||||
|
||||
/*********************************** Locals ***********************************/
|
||||
|
||||
static websUrlHandlerType *websUrlHandler; /* URL handler list */
|
||||
static int websUrlHandlerMax; /* Number of entries */
|
||||
static int urlHandlerOpenCount = 0; /* count of apps */
|
||||
|
||||
/**************************** Forward Declarations ****************************/
|
||||
|
||||
static int websUrlHandlerSort(const void *p1, const void *p2);
|
||||
static int websPublishHandler(webs_t wp, char_t *urlPrefix, char_t *webDir,
|
||||
int sid, char_t *url, char_t *path, char_t *query);
|
||||
static char_t *websCondenseMultipleChars(char_t *strToCondense, char_t cCondense);
|
||||
|
||||
/*********************************** Code *************************************/
|
||||
/*
|
||||
* Initialize the URL handler module
|
||||
*/
|
||||
|
||||
int websUrlHandlerOpen()
|
||||
{
|
||||
if (++urlHandlerOpenCount == 1) {
|
||||
websAspOpen();
|
||||
websUrlHandler = NULL;
|
||||
websUrlHandlerMax = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Close the URL handler module
|
||||
*/
|
||||
|
||||
void websUrlHandlerClose()
|
||||
{
|
||||
websUrlHandlerType *sp;
|
||||
|
||||
if (--urlHandlerOpenCount <= 0) {
|
||||
websAspClose();
|
||||
for (sp = websUrlHandler; sp < &websUrlHandler[websUrlHandlerMax];
|
||||
sp++) {
|
||||
bfree(B_L, sp->urlPrefix);
|
||||
if (sp->webDir) {
|
||||
bfree(B_L, sp->webDir);
|
||||
}
|
||||
}
|
||||
bfree(B_L, websUrlHandler);
|
||||
websUrlHandlerMax = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Define a new URL handler. urlPrefix is the URL prefix to match. webDir is
|
||||
* an optional root directory path for a web directory. arg is an optional
|
||||
* arg to pass to the URL handler. flags defines the matching order. Valid
|
||||
* flags include WEBS_HANDLER_LAST, WEBS_HANDLER_FIRST. If multiple users
|
||||
* specify last or first, their order is defined alphabetically by the
|
||||
* urlPrefix.
|
||||
*/
|
||||
|
||||
int websUrlHandlerDefine(char_t *urlPrefix, char_t *webDir, int arg,
|
||||
int (*handler)(webs_t wp, char_t *urlPrefix, char_t *webdir, int arg,
|
||||
char_t *url, char_t *path, char_t *query), int flags)
|
||||
{
|
||||
websUrlHandlerType *sp;
|
||||
int len;
|
||||
|
||||
a_assert(urlPrefix);
|
||||
a_assert(handler);
|
||||
|
||||
/*
|
||||
* Grow the URL handler array to create a new slot
|
||||
*/
|
||||
len = (websUrlHandlerMax + 1) * sizeof(websUrlHandlerType);
|
||||
if ((websUrlHandler = brealloc(B_L, websUrlHandler, len)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
sp = &websUrlHandler[websUrlHandlerMax++];
|
||||
memset(sp, 0, sizeof(websUrlHandlerType));
|
||||
|
||||
sp->urlPrefix = bstrdup(B_L, urlPrefix);
|
||||
sp->len = gstrlen(sp->urlPrefix);
|
||||
if (webDir) {
|
||||
sp->webDir = bstrdup(B_L, webDir);
|
||||
} else {
|
||||
sp->webDir = bstrdup(B_L, T(""));
|
||||
}
|
||||
sp->handler = handler;
|
||||
sp->arg = arg;
|
||||
sp->flags = flags;
|
||||
|
||||
/*
|
||||
* Sort in decreasing URL length order observing the flags for first and last
|
||||
*/
|
||||
qsort(websUrlHandler, websUrlHandlerMax, sizeof(websUrlHandlerType),
|
||||
websUrlHandlerSort);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Delete an existing URL handler. We don't reclaim the space of the old
|
||||
* handler, just NULL the entry. Return -1 if handler is not found.
|
||||
*/
|
||||
|
||||
int websUrlHandlerDelete(int (*handler)(webs_t wp, char_t *urlPrefix,
|
||||
char_t *webDir, int arg, char_t *url, char_t *path, char_t *query))
|
||||
{
|
||||
websUrlHandlerType *sp;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < websUrlHandlerMax; i++) {
|
||||
sp = &websUrlHandler[i];
|
||||
if (sp->handler == handler) {
|
||||
sp->handler = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Sort in decreasing URL length order observing the flags for first and last
|
||||
*/
|
||||
|
||||
static int websUrlHandlerSort(const void *p1, const void *p2)
|
||||
{
|
||||
websUrlHandlerType *s1, *s2;
|
||||
int rc;
|
||||
|
||||
a_assert(p1);
|
||||
a_assert(p2);
|
||||
|
||||
s1 = (websUrlHandlerType*) p1;
|
||||
s2 = (websUrlHandlerType*) p2;
|
||||
|
||||
if ((s1->flags & WEBS_HANDLER_FIRST) || (s2->flags & WEBS_HANDLER_LAST)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((s2->flags & WEBS_HANDLER_FIRST) || (s1->flags & WEBS_HANDLER_LAST)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((rc = gstrcmp(s1->urlPrefix, s2->urlPrefix)) == 0) {
|
||||
if (s1->len < s2->len) {
|
||||
return 1;
|
||||
} else if (s1->len > s2->len) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return -rc;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Publish a new web directory (Use the default URL handler)
|
||||
*/
|
||||
|
||||
int websPublish(char_t *urlPrefix, char_t *path)
|
||||
{
|
||||
return websUrlHandlerDefine(urlPrefix, path, 0, websPublishHandler, 0);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Return the directory for a given prefix. Ignore empty prefixes
|
||||
*/
|
||||
|
||||
char_t *websGetPublishDir(char_t *path, char_t **urlPrefix)
|
||||
{
|
||||
websUrlHandlerType *sp;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < websUrlHandlerMax; i++) {
|
||||
sp = &websUrlHandler[i];
|
||||
if (sp->urlPrefix[0] == '\0') {
|
||||
continue;
|
||||
}
|
||||
if (sp->handler && gstrncmp(sp->urlPrefix, path, sp->len) == 0) {
|
||||
if (urlPrefix) {
|
||||
*urlPrefix = sp->urlPrefix;
|
||||
}
|
||||
return sp->webDir;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Publish URL handler. We just patch the web page Directory and let the
|
||||
* default handler do the rest.
|
||||
*/
|
||||
|
||||
static int websPublishHandler(webs_t wp, char_t *urlPrefix, char_t *webDir,
|
||||
int sid, char_t *url, char_t *path, char_t *query)
|
||||
{
|
||||
int len;
|
||||
|
||||
a_assert(websValid(wp));
|
||||
a_assert(path);
|
||||
|
||||
/*
|
||||
* Trim the urlPrefix off the path and set the webdirectory. Add one to step
|
||||
* over the trailing '/'
|
||||
*/
|
||||
len = gstrlen(urlPrefix) + 1;
|
||||
websSetRequestPath(wp, webDir, &path[len]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* See if any valid handlers are defined for this request. If so, call them
|
||||
* and continue calling valid handlers until one accepts the request.
|
||||
* Return true if a handler was invoked, else return FALSE.
|
||||
*/
|
||||
|
||||
int websUrlHandlerRequest(webs_t wp)
|
||||
{
|
||||
websUrlHandlerType *sp;
|
||||
int i, first;
|
||||
|
||||
a_assert(websValid(wp));
|
||||
|
||||
/*
|
||||
* Delete the socket handler as we don't want to start reading any
|
||||
* data on the connection as it may be for the next pipelined HTTP/1.1
|
||||
* request if using Keep Alive
|
||||
*/
|
||||
socketDeleteHandler(wp->sid);
|
||||
wp->state = WEBS_PROCESSING;
|
||||
websStats.handlerHits++;
|
||||
|
||||
websSetRequestPath(wp, websGetDefaultDir(), NULL);
|
||||
|
||||
/*
|
||||
* Eliminate security hole
|
||||
*/
|
||||
websCondenseMultipleChars(wp->path, '/');
|
||||
websCondenseMultipleChars(wp->url, '/');
|
||||
|
||||
/*
|
||||
* We loop over each handler in order till one accepts the request.
|
||||
* The security handler will handle the request if access is NOT allowed.
|
||||
*/
|
||||
first = 1;
|
||||
for (i = 0; i < websUrlHandlerMax; i++) {
|
||||
sp = &websUrlHandler[i];
|
||||
if (sp->handler && gstrncmp(sp->urlPrefix, wp->path, sp->len) == 0) {
|
||||
if (first) {
|
||||
websSetEnv(wp);
|
||||
first = 0;
|
||||
}
|
||||
if ((*sp->handler)(wp, sp->urlPrefix, sp->webDir, sp->arg,
|
||||
wp->url, wp->path, wp->query)) {
|
||||
return 1;
|
||||
}
|
||||
if (!websValid(wp)) {
|
||||
trace(0,
|
||||
T("webs: handler %s called websDone, but didn't return 1\n"),
|
||||
sp->urlPrefix);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If no handler processed the request, then return an error. Note: It is
|
||||
* the handlers responsibility to call websDone
|
||||
*/
|
||||
if (i >= websUrlHandlerMax) {
|
||||
websError(wp, 200, T("No handler for this URL %s"), wp->url);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef OBSOLETE_CODE
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Tidy up the URL path. Return -1 if the URL is bad.
|
||||
* Used to eliminate repeated directory delimiters ('/').
|
||||
*/
|
||||
|
||||
static int websTidyUrl(webs_t wp)
|
||||
{
|
||||
char_t *parts[64]; /* Array of ptr's to URL parts */
|
||||
char_t *token, *url, *tidyurl;
|
||||
int i, len, npart;
|
||||
|
||||
a_assert(websValid(wp));
|
||||
|
||||
/*
|
||||
* Copy the string so we don't destroy the original (yet)
|
||||
*/
|
||||
url = bstrdup(B_L, wp->url);
|
||||
websDecodeUrl(url, url, gstrlen(url));
|
||||
|
||||
len = npart = 0;
|
||||
parts[0] = NULL;
|
||||
token = gstrtok(url, T("/"));
|
||||
|
||||
/*
|
||||
* Look at each directory segment and process "." and ".." segments
|
||||
* Don't allow the browser to pop outside the root web.
|
||||
*/
|
||||
while (token != NULL) {
|
||||
if (gstrcmp(token, T("..")) == 0) {
|
||||
if (npart > 0) {
|
||||
npart--;
|
||||
}
|
||||
|
||||
} else if (gstrcmp(token, T(".")) != 0) {
|
||||
parts[npart] = token;
|
||||
len += gstrlen(token) + 1;
|
||||
npart++;
|
||||
}
|
||||
token = gstrtok(NULL, T("/"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Re-construct URL. Need extra space all "/" and null.
|
||||
*/
|
||||
if (npart || (gstrcmp(url, T("/")) == 0) || (url[0] == '\0')) {
|
||||
tidyurl = balloc(B_L, (len + 2) * sizeof(char_t));
|
||||
*tidyurl = '\0';
|
||||
|
||||
for (i = 0; i < npart; i++) {
|
||||
gstrcat(tidyurl, T("/"));
|
||||
gstrcat(tidyurl, parts[i]);
|
||||
}
|
||||
|
||||
bfree(B_L, url);
|
||||
|
||||
bfree(B_L, wp->url);
|
||||
wp->url = tidyurl;
|
||||
return 0;
|
||||
} else {
|
||||
bfree(B_L, url);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Convert multiple adjacent occurrences of a given character to a single
|
||||
* instance.
|
||||
*/
|
||||
|
||||
static char_t *websCondenseMultipleChars(char_t *strToCondense, char_t cCondense)
|
||||
{
|
||||
if (strToCondense != NULL) {
|
||||
char_t *pStr, *pScan;
|
||||
|
||||
pStr = pScan = strToCondense;
|
||||
|
||||
while (*pScan && *pStr) {
|
||||
/*
|
||||
* Advance scan pointer over multiple occurences of condense character
|
||||
*/
|
||||
while ((*pScan == cCondense) && (*(pScan + 1) == cCondense)) {
|
||||
pScan++;
|
||||
}
|
||||
/*
|
||||
* Copy character if an advance of the scan pointer has occurred
|
||||
*/
|
||||
if (pStr != pScan) {
|
||||
*pStr = *pScan;
|
||||
}
|
||||
|
||||
pScan++;
|
||||
pStr++;
|
||||
}
|
||||
/*
|
||||
* Zero terminate string if multiple adjacent characters were found and condensed
|
||||
*/
|
||||
if (pStr != pScan) {
|
||||
*pStr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return strToCondense;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,282 +0,0 @@
|
||||
License Agreement
|
||||
|
||||
THIS LICENSE ALLOWS ONLY THE LIMITED USE OF GO AHEAD SOFTWARE,
|
||||
INC. PROPRIETARY CODE. PLEASE CAREFULLY READ THIS AGREEMENT AS IT
|
||||
PERTAINS TO THIS LICENSE, YOU CERTIFY THAT YOU WILL USE THE SOFTWARE
|
||||
ONLY IN THE MANNER PERMITTED HEREIN.
|
||||
|
||||
1. Definitions.
|
||||
|
||||
1.1 "Documentation" means any documentation GoAhead includes with the
|
||||
Original Code.
|
||||
|
||||
1.2 "GoAhead" means Go Ahead Software, Inc.
|
||||
|
||||
1.3 "Intellectual Property Rights" means all rights, whether now existing
|
||||
or hereinafter acquired, in and to trade secrets, patents, copyrights,
|
||||
trademarks, know-how, as well as moral rights and similar rights of any
|
||||
type under the laws of any governmental authority, domestic or foreign,
|
||||
including rights in and to all applications and registrations relating
|
||||
to any of the foregoing.
|
||||
|
||||
1.4 "License" or "Agreement" means this document.
|
||||
|
||||
1.5 "Modifications" means any addition to or deletion from the substance
|
||||
or structure of either the Original Code or any previous Modifications.
|
||||
|
||||
1.6 "Original Code" means the Source Code to GoAhead<61>s proprietary
|
||||
computer software entitled GoAhead WebServer.
|
||||
|
||||
1.7 "Response Header" means the first portion of the response message
|
||||
output by the GoAhead WebServer, containing but not limited to, header
|
||||
fields for date, content-type, server identification and cache control.
|
||||
|
||||
1.8 "Server Identification Field" means the field in the Response Header
|
||||
which contains the text "Server: GoAhead-Webs".
|
||||
|
||||
1.9 "You" means an individual or a legal entity exercising rights under,
|
||||
and complying with all of the terms of, this license or a future version
|
||||
of this license. For legal entities, "You" includes any entity which
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct or
|
||||
indirect, to cause the direction or management of such entity, whether
|
||||
by contract or otherwise, or (b) ownership of fifty percent (50%) or
|
||||
more of the outstanding shares or beneficial ownership of such entity.
|
||||
|
||||
2. Source Code License.
|
||||
|
||||
2.1 Limited Source Code Grant.
|
||||
|
||||
GoAhead hereby grants You a world-wide, royalty-free, non-exclusive
|
||||
license, subject to third party intellectual property claims, to use,
|
||||
reproduce, modify, copy and distribute the Original Code.
|
||||
|
||||
2.2 Binary Code.
|
||||
|
||||
GoAhead hereby grants You a world-wide, royalty-free, non-exclusive
|
||||
license to copy and distribute the binary code versions of the Original
|
||||
Code together with Your Modifications.
|
||||
|
||||
2.3 License Back to GoAhead.
|
||||
|
||||
You hereby grant in both source code and binary code to GoAhead a
|
||||
world-wide, royalty-free, non-exclusive license to copy, modify, display,
|
||||
use and sublicense any Modifications You make that are distributed or
|
||||
planned for distribution. Within 30 days of either such event, You
|
||||
agree to ship to GoAhead a file containing the Modifications (in a media
|
||||
to be determined by the parties), including any programmers<72> notes and
|
||||
other programmers<72> materials. Additionally, You will provide to GoAhead
|
||||
a complete description of the product, the product code or model number,
|
||||
the date on which the product is initially shipped, and a contact name,
|
||||
phone number and e-mail address for future correspondence. GoAhead will
|
||||
keep confidential all data specifically marked as such.
|
||||
|
||||
2.4 Restrictions on Use.
|
||||
|
||||
You may sublicense Modifications to third parties such as subcontractors
|
||||
or OEM's provided that You enter into license agreements with such third
|
||||
parties that bind such third parties to all the obligations under this
|
||||
Agreement applicable to you and that are otherwise substantially similar
|
||||
in scope and application to this Agreement.
|
||||
|
||||
3. Term.
|
||||
|
||||
This Agreement and license are effective from the time You accept the
|
||||
terms of this Agreement until this Agreement is terminated. You may
|
||||
terminate this Agreement at any time by uninstalling or destroying
|
||||
all copies of the Original Code including any and all binary versions
|
||||
and removing any Modifications to the Original Code existing in any
|
||||
products. This Agreement will terminate immediately and without further
|
||||
notice if You fail to comply with any provision of this Agreement. All
|
||||
restrictions on use, and all other provisions that may reasonably
|
||||
be interpreted to survive termination of this Agreement, will survive
|
||||
termination of this Agreement for any reason. Upon termination, You agree
|
||||
to uninstall or destroy all copies of the Original Code, Modifications,
|
||||
and Documentation.
|
||||
|
||||
4. Trademarks and Brand.
|
||||
|
||||
4.1 License and Use.
|
||||
|
||||
GoAhead hereby grants to You a limited world-wide, royalty-free,
|
||||
non-exclusive license to use the GoAhead trade names, trademarks, logos,
|
||||
service marks and product designations posted in Exhibit A (collectively,
|
||||
the "GoAhead Marks") in connection with the activities by You under this
|
||||
Agreement. Additionally, GoAhead grants You a license under the terms
|
||||
above to such GoAhead trademarks as shall be identified at a URL (the
|
||||
"URL") provided by GoAhead. The use by You of GoAhead Marks shall be in
|
||||
accordance with GoAhead<61>s trademark policies regarding trademark usage
|
||||
as established at the web site designated by the URL, or as otherwise
|
||||
communicated to You by GoAhead at its sole discretion. You understand and
|
||||
agree that any use of GoAhead Marks in connection with this Agreement
|
||||
shall not create any right, title or interest in or to such GoAhead
|
||||
Marks and that all such use and goodwill associated with GoAhead Marks
|
||||
will inure to the benefit of GoAhead.
|
||||
|
||||
4.2 Promotion by You of GoAhead WebServer Mark.
|
||||
|
||||
In consideration for the licenses granted by GoAhead to You herein, You
|
||||
agree to notify GoAhead when You incorporate the GoAhead WebServer in
|
||||
Your product and to inform GoAhead when such product begins to ship. You
|
||||
agree to promote the Original Code by prominently and visibly displaying
|
||||
a graphic of the GoAhead WebServer mark on the initial web page of Your
|
||||
product that is displayed each time a user connects to it. You also agree
|
||||
that GoAhead may identify your company as a user of the GoAhead WebServer
|
||||
in conjunction with its own marketing efforts. You may further promote
|
||||
the Original Code by displaying the GoAhead WebServer mark in marketing
|
||||
and promotional materials such as the home page of your web site or web
|
||||
pages promoting the product.
|
||||
|
||||
4.3 Placement of Copyright Notice by You.
|
||||
|
||||
You agree to include copies of the following notice (the "Notice")
|
||||
regarding proprietary rights in all copies of the products that You
|
||||
distribute, as follows: (i) embedded in the object code; and (ii) on
|
||||
the title pages of all documentation. Furthermore, You agree to use
|
||||
commercially reasonable efforts to cause any licensees of your products
|
||||
to embed the Notice in object code and on the title pages or relevant
|
||||
documentation. The Notice is as follows: Copyright (c) 20xx GoAhead
|
||||
Software, Inc. All Rights Reserved. Unless GoAhead otherwise instructs,
|
||||
the year 20xx is to be replaced with the year during which the release of
|
||||
the Original Code containing the notice is issued by GoAhead. If this year
|
||||
is not supplied with Documentation, GoAhead will supply it upon request.
|
||||
|
||||
4.4 No Modifications to Server Identification Field.
|
||||
|
||||
You agree not to remove or modify the Server identification Field
|
||||
contained in the Response Header as defined in Section 1.6 and 1.7.
|
||||
|
||||
5. Warranty Disclaimers.
|
||||
|
||||
THE ORIGINAL CODE, THE DOCUMENTATION AND THE MEDIA UPON WHICH THE ORIGINAL
|
||||
CODE IS RECORDED (IF ANY) ARE PROVIDED "AS IS" AND WITHOUT WARRANTIES OF
|
||||
ANY KIND, EXPRESS, STATUTORY OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
|
||||
The entire risk as to the quality and performance of the Original Code
|
||||
(including any Modifications You make) and the Documentation is with
|
||||
You. Should the Original Code or the Documentation prove defective,
|
||||
You (and not GoAhead or its distributors, licensors or dealers) assume
|
||||
the entire cost of all necessary servicing or repair. GoAhead does not
|
||||
warrant that the functions contained in the Original Code will meet your
|
||||
requirements or operate in the combination that You may select for use,
|
||||
that the operation of the Original Code will be uninterrupted or error
|
||||
free, or that defects in the Original Code will be corrected. No oral
|
||||
or written statement by GoAhead or by a representative of GoAhead shall
|
||||
create a warranty or increase the scope of this warranty.
|
||||
|
||||
GOAHEAD DOES NOT WARRANT THE ORIGINAL CODE AGAINST INFRINGEMENT OR THE
|
||||
LIKE WITH RESPECT TO ANY COPYRIGHT, PATENT, TRADE SECRET, TRADEMARK
|
||||
OR OTHER PROPRIETARY RIGHT OF ANY THIRD PARTY AND DOES NOT WARRANT
|
||||
THAT THE ORIGINAL CODE DOES NOT INCLUDE ANY VIRUS, SOFTWARE ROUTINE
|
||||
OR OTHER SOFTWARE DESIGNED TO PERMIT UNAUTHORIZED ACCESS, TO DISABLE,
|
||||
ERASE OR OTHERWISE HARM SOFTWARE, HARDWARE OR DATA, OR TO PERFORM ANY
|
||||
OTHER SUCH ACTIONS.
|
||||
|
||||
Any warranties that by law survive the foregoing disclaimers shall
|
||||
terminate ninety (90) days from the date You received the Original Code.
|
||||
|
||||
6. Limitation of Liability.
|
||||
|
||||
YOUR SOLE REMEDIES AND GOAHEAD'S ENTIRE LIABILITY ARE SET FORTH ABOVE. IN
|
||||
NO EVENT WILL GOAHEAD OR ITS DISTRIBUTORS OR DEALERS BE LIABLE FOR
|
||||
DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES RESULTING FROM
|
||||
THE USE OF THE ORIGINAL CODE, THE INABILITY TO USE THE ORIGINAL CODE,
|
||||
OR ANY DEFECT IN THE ORIGINAL CODE, INCLUDING ANY LOST PROFITS, EVEN IF
|
||||
THEY HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You agree that GoAhead and its distributors and dealers will not be
|
||||
LIABLE for defense or indemnity with respect to any claim against You
|
||||
by any third party arising from your possession or use of the Original
|
||||
Code or the Documentation.
|
||||
|
||||
In no event will GoAhead<61>s total liability to You for all damages, losses,
|
||||
and causes of action (whether in contract, tort, including negligence,
|
||||
or otherwise) exceed the amount You paid for this product.
|
||||
|
||||
SOME STATES DO NOT ALLOW LIMITATIONS ON HOW LONG AN IMPLIED WARRANTY
|
||||
LASTS, AND SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION
|
||||
OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THE ABOVE LIMITATIONS OR
|
||||
EXCLUSIONS MAY NOT APPLY TO YOU. THIS WARRANTY GIVES YOU SPECIFIC LEGAL
|
||||
RIGHTS AND YOU MAY ALSO HAVE OTHER RIGHTS WHICH VARY FROM STATE TO STATE.
|
||||
|
||||
7. Indemnification by You.
|
||||
|
||||
You agree to indemnify and hold GoAhead harmless against any and all
|
||||
claims, losses, damages and costs (including legal expenses and reasonable
|
||||
counsel fees) arising out of any claim of a third party with respect to
|
||||
the contents of the Your products, and any intellectual property rights
|
||||
or other rights or interests related thereto.
|
||||
|
||||
8. High Risk Activities.
|
||||
|
||||
The Original Code is not fault-tolerant and is not designed , manufactured
|
||||
or intended for use or resale as online control equipment in hazardous
|
||||
environments requiring fail-safe performance, such as in the operation
|
||||
of nuclear facilities, aircraft navigation or communication systems,
|
||||
air traffic control, direct life support machines or weapons systems,
|
||||
in which the failure of the Original Code could lead directly to death,
|
||||
personal injury, or severe physical or environmental damage. GoAhead and
|
||||
its suppliers specifically disclaim any express or implied warranty of
|
||||
fitness for any high risk uses listed above.
|
||||
|
||||
9. Government Restricted Rights.
|
||||
|
||||
For units of the Department of Defense, use, duplication, or disclosure
|
||||
by the Government is subject to restrictions as set forth in subparagraph
|
||||
(c)(1)(ii) of the Rights in Technical Data and Computer Software clause
|
||||
at DFARS 252.227-7013. Contractor/manufacturer is GoAhead Software,
|
||||
Inc., 10900 N.E. 8th Street, Suite 750, Bellevue, Washington 98004.
|
||||
|
||||
If the Commercial Computer Software Restricted rights clause at FAR
|
||||
52.227-19 or its successors apply, the Software and Documentation
|
||||
constitute restricted computer software as defined in that clause and
|
||||
the Government shall not have the license for published software set
|
||||
forth in subparagraph (c)(3) of that clause.
|
||||
|
||||
The Original Code (i) was developed at private expense, and no part of it
|
||||
was developed with governmental funds; (ii) is a trade secret of GoAhead
|
||||
(or its licensor(s)) for all purposes of the Freedom of Information Act;
|
||||
(iii) is "restricted computer software" subject to limited utilization as
|
||||
provided in the contract between the vendor and the governmental entity;
|
||||
and (iv) in all respects is proprietary data belonging solely to GoAhead
|
||||
(or its licensor(s)).
|
||||
|
||||
10. Governing Law and Interpretation.
|
||||
|
||||
This Agreement shall be interpreted under and governed by the laws of the
|
||||
State of Washington, without regard to its rules governing the conflict of
|
||||
laws. If any provision of this Agreement is held illegal or unenforceable
|
||||
by a court or tribunal of competent jurisdiction, the remaining provisions
|
||||
of this Agreement shall remain in effect and the invalid provision deemed
|
||||
modified to the least degree necessary to remedy such invalidity.
|
||||
|
||||
11. Entire Agreement.
|
||||
|
||||
This Agreement is the complete agreement between GoAhead and You and
|
||||
supersedes all prior agreements, oral or written, with respect to the
|
||||
subject matter hereof.
|
||||
|
||||
If You have any questions concerning this Agreement, You may write to
|
||||
GoAhead Software, Inc., 10900 N.E. 8th Street, Suite 750, Bellevue,
|
||||
Washington 98004 or send e-mail to info@goahead.com.
|
||||
|
||||
BY CLICKING ON THE "Register" BUTTON ON THE REGISTRATION FORM, YOU
|
||||
ACCEPT AND AGREE TO BE BOUND BY ALL OF THE TERMS AND CONDITIONS SET
|
||||
FORTH IN THIS AGREEMENT. IF YOU DO NOT WISH TO ACCEPT THIS LICENSE OR
|
||||
YOU DO NOT QUALIFY FOR A LICENSE BASED ON THE TERMS SET FORTH ABOVE,
|
||||
YOU MUST NOT CLICK THE "Register" BUTTON.
|
||||
|
||||
Exhibit A
|
||||
|
||||
GoAhead Trademarks, Logos, and Product Designation Information
|
||||
|
||||
|
||||
|
||||
|
||||
01/28/00
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/* MD5.H - header file for MD5C.C
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
|
||||
rights reserved.
|
||||
|
||||
License to copy and use this software is granted provided that it
|
||||
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
|
||||
Algorithm" in all material mentioning or referencing this software
|
||||
or this function.
|
||||
|
||||
License is also granted to make and use derivative works provided
|
||||
that such works are identified as "derived from the RSA Data
|
||||
Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||
mentioning or referencing the derived work.
|
||||
|
||||
RSA Data Security, Inc. makes no representations concerning either
|
||||
the merchantability of this software or the suitability of this
|
||||
software for any particular purpose. It is provided "as is"
|
||||
without express or implied warranty of any kind.
|
||||
|
||||
These notices must be retained in any copies of any part of this
|
||||
documentation and/or software.
|
||||
*/
|
||||
|
||||
#ifndef _h_MD5
|
||||
#define _h_MD5 1
|
||||
|
||||
#ifndef UINT4
|
||||
#define UINT4 unsigned long
|
||||
#endif
|
||||
|
||||
#ifndef POINTER
|
||||
#define POINTER unsigned char *
|
||||
#endif
|
||||
|
||||
/* MD5 context. */
|
||||
typedef struct {
|
||||
UINT4 state[4]; /* state (ABCD) */
|
||||
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
|
||||
unsigned char buffer[64]; /* input buffer */
|
||||
} MD5_CONTEXT;
|
||||
|
||||
extern void MD5Init (MD5_CONTEXT *);
|
||||
extern void MD5Update (MD5_CONTEXT *, unsigned char *, unsigned int);
|
||||
extern void MD5Final (unsigned char [16], MD5_CONTEXT *);
|
||||
|
||||
#endif /* _h_MD5 */
|
||||
@@ -1,337 +0,0 @@
|
||||
/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
|
||||
rights reserved.
|
||||
|
||||
License to copy and use this software is granted provided that it
|
||||
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
|
||||
Algorithm" in all material mentioning or referencing this software
|
||||
or this function.
|
||||
|
||||
License is also granted to make and use derivative works provided
|
||||
that such works are identified as "derived from the RSA Data
|
||||
Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||
mentioning or referencing the derived work.
|
||||
|
||||
RSA Data Security, Inc. makes no representations concerning either
|
||||
the merchantability of this software or the suitability of this
|
||||
software for any particular purpose. It is provided "as is"
|
||||
without express or implied warranty of any kind.
|
||||
|
||||
These notices must be retained in any copies of any part of this
|
||||
documentation and/or software.
|
||||
*/
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
/* Constants for MD5Transform routine.
|
||||
*/
|
||||
#define S11 7
|
||||
#define S12 12
|
||||
#define S13 17
|
||||
#define S14 22
|
||||
#define S21 5
|
||||
#define S22 9
|
||||
#define S23 14
|
||||
#define S24 20
|
||||
#define S31 4
|
||||
#define S32 11
|
||||
#define S33 16
|
||||
#define S34 23
|
||||
#define S41 6
|
||||
#define S42 10
|
||||
#define S43 15
|
||||
#define S44 21
|
||||
|
||||
static void MD5Transform (UINT4 [4], unsigned char [64]);
|
||||
static void Encode (unsigned char *, UINT4 *, unsigned int);
|
||||
static void Decode (UINT4 *, unsigned char *, unsigned int);
|
||||
static void MD5_memcpy (POINTER, POINTER, unsigned int);
|
||||
static void MD5_memset (POINTER, int, unsigned int);
|
||||
|
||||
static unsigned char PADDING[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/*
|
||||
* Note: The following MD5 macros can be implemented as functions
|
||||
* for code compactness, (at the expense of execution speed).
|
||||
*/
|
||||
|
||||
/* F, G, H and I are basic MD5 functions.
|
||||
*/
|
||||
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define I(x, y, z) ((y) ^ ((x) | (~z)))
|
||||
|
||||
/* ROTATE_LEFT rotates x left n bits.
|
||||
*/
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
|
||||
|
||||
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
|
||||
Rotation is separate from addition to prevent recomputation.
|
||||
*/
|
||||
#define FF(a, b, c, d, x, s, ac) { \
|
||||
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define GG(a, b, c, d, x, s, ac) { \
|
||||
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define HH(a, b, c, d, x, s, ac) { \
|
||||
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define II(a, b, c, d, x, s, ac) { \
|
||||
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
|
||||
/* MD5 initialization. Begins an MD5 operation, writing a new context.
|
||||
*/
|
||||
void MD5Init (context)
|
||||
MD5_CONTEXT *context; /* context */
|
||||
{
|
||||
context->count[0] = context->count[1] = 0;
|
||||
/* Load magic initialization constants.
|
||||
*/
|
||||
context->state[0] = 0x67452301;
|
||||
context->state[1] = 0xefcdab89;
|
||||
context->state[2] = 0x98badcfe;
|
||||
context->state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
/* MD5 block update operation. Continues an MD5 message-digest
|
||||
operation, processing another message block, and updating the
|
||||
context.
|
||||
*/
|
||||
void MD5Update (context, input, inputLen)
|
||||
MD5_CONTEXT *context; /* context */
|
||||
unsigned char *input; /* input block */
|
||||
unsigned int inputLen; /* length of input block */
|
||||
{
|
||||
unsigned int i, index, partLen;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
|
||||
|
||||
/* Update number of bits */
|
||||
if ((context->count[0] += ((UINT4)inputLen << 3))
|
||||
< ((UINT4)inputLen << 3))
|
||||
context->count[1]++;
|
||||
context->count[1] += ((UINT4)inputLen >> 29);
|
||||
|
||||
partLen = 64 - index;
|
||||
|
||||
/* Transform as many times as possible.
|
||||
*/
|
||||
if (inputLen >= partLen) {
|
||||
MD5_memcpy
|
||||
((POINTER)&context->buffer[index], (POINTER)input, partLen);
|
||||
MD5Transform (context->state, context->buffer);
|
||||
|
||||
for (i = partLen; i + 63 < inputLen; i += 64)
|
||||
MD5Transform (context->state, &input[i]);
|
||||
|
||||
index = 0;
|
||||
}
|
||||
else
|
||||
i = 0;
|
||||
|
||||
/* Buffer remaining input */
|
||||
MD5_memcpy
|
||||
((POINTER)&context->buffer[index], (POINTER)&input[i],
|
||||
inputLen-i);
|
||||
}
|
||||
|
||||
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
|
||||
the message digest and zeroizing the context.
|
||||
*/
|
||||
void MD5Final (digest, context)
|
||||
unsigned char digest[16]; /* message digest */
|
||||
MD5_CONTEXT *context; /* context */
|
||||
{
|
||||
unsigned char bits[8];
|
||||
unsigned int index, padLen;
|
||||
|
||||
/* Save number of bits */
|
||||
Encode (bits, context->count, 8);
|
||||
|
||||
/* Pad out to 56 mod 64.
|
||||
*/
|
||||
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
|
||||
padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||
MD5Update (context, PADDING, padLen);
|
||||
|
||||
/* Append length (before padding) */
|
||||
MD5Update (context, bits, 8);
|
||||
/* Store state in digest */
|
||||
Encode (digest, context->state, 16);
|
||||
|
||||
/* Zeroize sensitive information.
|
||||
*/
|
||||
MD5_memset ((POINTER)context, 0, sizeof (*context));
|
||||
}
|
||||
|
||||
/* MD5 basic transformation. Transforms state based on block.
|
||||
*/
|
||||
static void MD5Transform (state, block)
|
||||
UINT4 state[4];
|
||||
unsigned char block[64];
|
||||
{
|
||||
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
|
||||
|
||||
Decode (x, block, 64);
|
||||
|
||||
/* Round 1 */
|
||||
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
|
||||
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
|
||||
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
|
||||
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
|
||||
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
|
||||
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
|
||||
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
|
||||
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
|
||||
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
|
||||
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
|
||||
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
|
||||
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
|
||||
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
|
||||
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
|
||||
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
|
||||
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
|
||||
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
|
||||
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
|
||||
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
|
||||
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
|
||||
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
|
||||
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
|
||||
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
|
||||
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
|
||||
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
|
||||
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
|
||||
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
|
||||
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
|
||||
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
|
||||
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
|
||||
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
|
||||
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
|
||||
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
|
||||
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
|
||||
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
|
||||
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
|
||||
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
|
||||
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
|
||||
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
|
||||
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
|
||||
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
|
||||
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
|
||||
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
|
||||
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
|
||||
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
|
||||
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
|
||||
|
||||
/* Round 4 */
|
||||
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
|
||||
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
|
||||
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
|
||||
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
|
||||
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
|
||||
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
|
||||
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
|
||||
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
|
||||
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
|
||||
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
|
||||
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
|
||||
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
|
||||
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
|
||||
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
|
||||
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
|
||||
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
|
||||
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
|
||||
/* Zeroize sensitive information.
|
||||
*/
|
||||
MD5_memset ((POINTER)x, 0, sizeof (x));
|
||||
}
|
||||
|
||||
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
|
||||
a multiple of 4.
|
||||
*/
|
||||
static void Encode (output, input, len)
|
||||
unsigned char *output;
|
||||
UINT4 *input;
|
||||
unsigned int len;
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4) {
|
||||
output[j] = (unsigned char)(input[i] & 0xff);
|
||||
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
|
||||
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
|
||||
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
/* Decodes input (unsigned char) into output (UINT4). Assumes len is
|
||||
a multiple of 4.
|
||||
*/
|
||||
static void Decode (output, input, len)
|
||||
UINT4 *output;
|
||||
unsigned char *input;
|
||||
unsigned int len;
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4)
|
||||
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
|
||||
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
|
||||
}
|
||||
|
||||
/* Note: Replace "for loop" with standard memcpy if possible.
|
||||
*/
|
||||
|
||||
static void MD5_memcpy (output, input, len)
|
||||
POINTER output;
|
||||
POINTER input;
|
||||
unsigned int len;
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
output[i] = input[i];
|
||||
}
|
||||
|
||||
/* Note: Replace "for loop" with standard memset if possible.
|
||||
*/
|
||||
static void MD5_memset (output, value, len)
|
||||
POINTER output;
|
||||
int value;
|
||||
unsigned int len;
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
((char *)output)[i] = (char)value;
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* mime.c -- Web server mime types
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* Mime types and file extensions. This module maps URL extensions to
|
||||
* content types.
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#include "wsIntrn.h"
|
||||
|
||||
/******************************** Global Data *********************************/
|
||||
/*
|
||||
* Addd entries to the MimeList as required for your content
|
||||
*/
|
||||
|
||||
|
||||
websMimeType websMimeList[] = {
|
||||
{ T("application/java"), T(".class") },
|
||||
{ T("application/java"), T(".jar") },
|
||||
{ T("text/html"), T(".asp") },
|
||||
{ T("text/html"), T(".htm") },
|
||||
{ T("text/html"), T(".html") },
|
||||
{ T("image/gif"), T(".gif") },
|
||||
{ T("image/jpeg"), T(".jpg") },
|
||||
{ T("text/css"), T(".css") },
|
||||
{ T("text/plain"), T(".txt") },
|
||||
{ T("application/x-javascript"), T(".js") },
|
||||
|
||||
#ifdef MORE_MIME_TYPES
|
||||
{ T("application/binary"), T(".exe") },
|
||||
{ T("application/compress"), T(".z") },
|
||||
{ T("application/gzip"), T(".gz") },
|
||||
{ T("application/octet-stream"), T(".bin") },
|
||||
{ T("application/oda"), T(".oda") },
|
||||
{ T("application/pdf"), T(".pdf") },
|
||||
{ T("application/postscript"), T(".ai") },
|
||||
{ T("application/postscript"), T(".eps") },
|
||||
{ T("application/postscript"), T(".ps") },
|
||||
{ T("application/rtf"), T(".rtf") },
|
||||
{ T("application/x-bcpio"), T(".bcpio") },
|
||||
{ T("application/x-cpio"), T(".cpio") },
|
||||
{ T("application/x-csh"), T(".csh") },
|
||||
{ T("application/x-dvi"), T(".dvi") },
|
||||
{ T("application/x-gtar"), T(".gtar") },
|
||||
{ T("application/x-hdf"), T(".hdf") },
|
||||
{ T("application/x-latex"), T(".latex") },
|
||||
{ T("application/x-mif"), T(".mif") },
|
||||
{ T("application/x-netcdf"), T(".nc") },
|
||||
{ T("application/x-netcdf"), T(".cdf") },
|
||||
{ T("application/x-ns-proxy-autoconfig"), T(".pac") },
|
||||
{ T("application/x-patch"), T(".patch") },
|
||||
{ T("application/x-sh"), T(".sh") },
|
||||
{ T("application/x-shar"), T(".shar") },
|
||||
{ T("application/x-sv4cpio"), T(".sv4cpio") },
|
||||
{ T("application/x-sv4crc"), T(".sv4crc") },
|
||||
{ T("application/x-tar"), T(".tar") },
|
||||
{ T("application/x-tcl"), T(".tcl") },
|
||||
{ T("application/x-tex"), T(".tex") },
|
||||
{ T("application/x-texinfo"), T(".texinfo") },
|
||||
{ T("application/x-texinfo"), T(".texi") },
|
||||
{ T("application/x-troff"), T(".t") },
|
||||
{ T("application/x-troff"), T(".tr") },
|
||||
{ T("application/x-troff"), T(".roff") },
|
||||
{ T("application/x-troff-man"), T(".man") },
|
||||
{ T("application/x-troff-me"), T(".me") },
|
||||
{ T("application/x-troff-ms"), T(".ms") },
|
||||
{ T("application/x-ustar"), T(".ustar") },
|
||||
{ T("application/x-wais-source"), T(".src") },
|
||||
{ T("application/zip"), T(".zip") },
|
||||
{ T("audio/basic"), T(".au snd") },
|
||||
{ T("audio/x-aiff"), T(".aif") },
|
||||
{ T("audio/x-aiff"), T(".aiff") },
|
||||
{ T("audio/x-aiff"), T(".aifc") },
|
||||
{ T("audio/x-wav"), T(".wav") },
|
||||
{ T("audio/x-wav"), T(".ram") },
|
||||
{ T("image/ief"), T(".ief") },
|
||||
{ T("image/jpeg"), T(".jpeg") },
|
||||
{ T("image/jpeg"), T(".jpe") },
|
||||
{ T("image/tiff"), T(".tiff") },
|
||||
{ T("image/tiff"), T(".tif") },
|
||||
{ T("image/x-cmu-raster"), T(".ras") },
|
||||
{ T("image/x-portable-anymap"), T(".pnm") },
|
||||
{ T("image/x-portable-bitmap"), T(".pbm") },
|
||||
{ T("image/x-portable-graymap"), T(".pgm") },
|
||||
{ T("image/x-portable-pixmap"), T(".ppm") },
|
||||
{ T("image/x-rgb"), T(".rgb") },
|
||||
{ T("image/x-xbitmap"), T(".xbm") },
|
||||
{ T("image/x-xpixmap"), T(".xpm") },
|
||||
{ T("image/x-xwindowdump"), T(".xwd") },
|
||||
{ T("text/html"), T(".cfm") },
|
||||
{ T("text/html"), T(".shtm") },
|
||||
{ T("text/html"), T(".shtml") },
|
||||
{ T("text/richtext"), T(".rtx") },
|
||||
{ T("text/tab-separated-values"), T(".tsv") },
|
||||
{ T("text/x-setext"), T(".etx") },
|
||||
{ T("video/mpeg"), T(".mpeg mpg mpe") },
|
||||
{ T("video/quicktime"), T(".qt") },
|
||||
{ T("video/quicktime"), T(".mov") },
|
||||
{ T("video/x-msvideo"), T(".avi") },
|
||||
{ T("video/x-sgi-movie"), T(".movie") },
|
||||
#endif
|
||||
{ NULL, NULL},
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -1,675 +0,0 @@
|
||||
/*
|
||||
* misc.c -- Miscellaneous routines.
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#ifdef UEMF
|
||||
#include "uemf.h"
|
||||
#else
|
||||
#include "basic/basicInternal.h"
|
||||
#endif
|
||||
|
||||
/********************************* Defines ************************************/
|
||||
/*
|
||||
* Sprintf buffer structure. Make the increment 64 so that
|
||||
* a balloc can use a 64 byte block.
|
||||
*/
|
||||
|
||||
#define STR_REALLOC 0x1 /* Reallocate the buffer as required */
|
||||
#define STR_INC 64 /* Growth increment */
|
||||
|
||||
typedef struct {
|
||||
char_t *s; /* Pointer to buffer */
|
||||
int size; /* Current buffer size */
|
||||
int max; /* Maximum buffer size */
|
||||
int count; /* Buffer count */
|
||||
int flags; /* Allocation flags */
|
||||
} strbuf_t;
|
||||
|
||||
/*
|
||||
* Sprintf formatting flags
|
||||
*/
|
||||
enum flag {
|
||||
flag_none = 0,
|
||||
flag_minus = 1,
|
||||
flag_plus = 2,
|
||||
flag_space = 4,
|
||||
flag_hash = 8,
|
||||
flag_zero = 16,
|
||||
flag_short = 32,
|
||||
flag_long = 64
|
||||
};
|
||||
|
||||
/************************** Forward Declarations ******************************/
|
||||
|
||||
static int dsnprintf(char_t **s, int size, char_t *fmt, va_list arg,
|
||||
int msize);
|
||||
#if !defined(__rtems__)
|
||||
static int strnlen(char_t *s, unsigned int n);
|
||||
#endif
|
||||
static void put_char(strbuf_t *buf, char_t c);
|
||||
static void put_string(strbuf_t *buf, char_t *s, int len,
|
||||
int width, int prec, enum flag f);
|
||||
static void put_ulong(strbuf_t *buf, unsigned long int value, int base,
|
||||
int upper, char_t *prefix, int width, int prec, enum flag f);
|
||||
|
||||
/************************************ Code ************************************/
|
||||
/*
|
||||
* "basename" returns a pointer to the last component of a pathname
|
||||
* LINUX, LynxOS and Mac OS X have their own basename function
|
||||
*/
|
||||
|
||||
#if (!defined (LINUX) && !defined (LYNX) && !defined (MACOSX))
|
||||
char_t *basename(char_t *name)
|
||||
{
|
||||
char_t *cp;
|
||||
|
||||
#if (defined (NW) || defined (WIN))
|
||||
if (((cp = gstrrchr(name, '\\')) == NULL) &&
|
||||
((cp = gstrrchr(name, '/')) == NULL)) {
|
||||
return name;
|
||||
#else
|
||||
if ((cp = gstrrchr(name, '/')) == NULL) {
|
||||
return name;
|
||||
#endif
|
||||
} else if (*(cp + 1) == '\0' && cp == name) {
|
||||
return name;
|
||||
} else if (*(cp + 1) == '\0' && cp != name) {
|
||||
return T("");
|
||||
} else {
|
||||
return ++cp;
|
||||
}
|
||||
}
|
||||
#endif /* ! LINUX & ! LYNX & ! MACOSX */
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Returns a pointer to the directory component of a pathname. bufsize is
|
||||
* the size of the buffer in BYTES!
|
||||
*/
|
||||
|
||||
char_t *dirname(char_t *buf, char_t *name, int bufsize)
|
||||
{
|
||||
char_t *cp;
|
||||
int len;
|
||||
|
||||
a_assert(name);
|
||||
a_assert(buf);
|
||||
a_assert(bufsize > 0);
|
||||
|
||||
#if (defined (WIN) || defined (NW))
|
||||
if ((cp = gstrrchr(name, '/')) == NULL &&
|
||||
(cp = gstrrchr(name, '\\')) == NULL)
|
||||
#else
|
||||
if ((cp = gstrrchr(name, '/')) == NULL)
|
||||
#endif
|
||||
{
|
||||
gstrcpy(buf, T("."));
|
||||
return buf;
|
||||
}
|
||||
|
||||
if ((*(cp + 1) == '\0' && cp == name)) {
|
||||
gstrncpy(buf, T("."), TSZ(bufsize));
|
||||
gstrcpy(buf, T("."));
|
||||
return buf;
|
||||
}
|
||||
|
||||
len = cp - name;
|
||||
|
||||
if (len < bufsize) {
|
||||
gstrncpy(buf, name, len);
|
||||
buf[len] = '\0';
|
||||
} else {
|
||||
gstrncpy(buf, name, TSZ(bufsize));
|
||||
buf[bufsize - 1] = '\0';
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* sprintf and vsprintf are bad, ok. You can easily clobber memory. Use
|
||||
* fmtAlloc and fmtValloc instead! These functions do _not_ support floating
|
||||
* point, like %e, %f, %g...
|
||||
*/
|
||||
|
||||
int fmtAlloc(char_t **s, int n, char_t *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
a_assert(s);
|
||||
a_assert(fmt);
|
||||
|
||||
*s = NULL;
|
||||
va_start(ap, fmt);
|
||||
result = dsnprintf(s, n, fmt, ap, 0);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Support a static buffer version for small buffers only!
|
||||
*/
|
||||
|
||||
int fmtStatic(char_t *s, int n, char_t *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
a_assert(s);
|
||||
a_assert(fmt);
|
||||
a_assert(n <= 256);
|
||||
|
||||
if (n <= 0) {
|
||||
return -1;
|
||||
}
|
||||
va_start(ap, fmt);
|
||||
result = dsnprintf(&s, n, fmt, ap, 0);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* This function appends the formatted string to the supplied string,
|
||||
* reallocing if required.
|
||||
*/
|
||||
|
||||
int fmtRealloc(char_t **s, int n, int msize, char_t *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
a_assert(s);
|
||||
a_assert(fmt);
|
||||
|
||||
if (msize == -1) {
|
||||
*s = NULL;
|
||||
}
|
||||
va_start(ap, fmt);
|
||||
result = dsnprintf(s, n, fmt, ap, msize);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* A vsprintf replacement.
|
||||
*/
|
||||
|
||||
int fmtValloc(char_t **s, int n, char_t *fmt, va_list arg)
|
||||
{
|
||||
a_assert(s);
|
||||
a_assert(fmt);
|
||||
|
||||
*s = NULL;
|
||||
return dsnprintf(s, n, fmt, arg, 0);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Dynamic sprintf implementation. Supports dynamic buffer allocation.
|
||||
* This function can be called multiple times to grow an existing allocated
|
||||
* buffer. In this case, msize is set to the size of the previously allocated
|
||||
* buffer. The buffer will be realloced, as required. If msize is set, we
|
||||
* return the size of the allocated buffer for use with the next call. For
|
||||
* the first call, msize can be set to -1.
|
||||
*/
|
||||
|
||||
static int dsnprintf(char_t **s, int size, char_t *fmt, va_list arg, int msize)
|
||||
{
|
||||
strbuf_t buf;
|
||||
char_t c;
|
||||
|
||||
a_assert(s);
|
||||
a_assert(fmt);
|
||||
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
buf.s = *s;
|
||||
|
||||
if (*s == NULL || msize != 0) {
|
||||
buf.max = size;
|
||||
buf.flags |= STR_REALLOC;
|
||||
if (msize != 0) {
|
||||
buf.size = max(msize, 0);
|
||||
}
|
||||
if (*s != NULL && msize != 0) {
|
||||
buf.count = gstrlen(*s);
|
||||
}
|
||||
} else {
|
||||
buf.size = size;
|
||||
}
|
||||
|
||||
while ((c = *fmt++) != '\0') {
|
||||
if (c != '%' || (c = *fmt++) == '%') {
|
||||
put_char(&buf, c);
|
||||
} else {
|
||||
enum flag f = flag_none;
|
||||
int width = 0;
|
||||
int prec = -1;
|
||||
for ( ; c != '\0'; c = *fmt++) {
|
||||
if (c == '-') {
|
||||
f |= flag_minus;
|
||||
} else if (c == '+') {
|
||||
f |= flag_plus;
|
||||
} else if (c == ' ') {
|
||||
f |= flag_space;
|
||||
} else if (c == '#') {
|
||||
f |= flag_hash;
|
||||
} else if (c == '0') {
|
||||
f |= flag_zero;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c == '*') {
|
||||
width = va_arg(arg, int);
|
||||
if (width < 0) {
|
||||
f |= flag_minus;
|
||||
width = -width;
|
||||
}
|
||||
c = *fmt++;
|
||||
} else {
|
||||
for ( ; gisdigit((int)c); c = *fmt++) {
|
||||
width = width * 10 + (c - '0');
|
||||
}
|
||||
}
|
||||
if (c == '.') {
|
||||
f &= ~flag_zero;
|
||||
c = *fmt++;
|
||||
if (c == '*') {
|
||||
prec = va_arg(arg, int);
|
||||
c = *fmt++;
|
||||
} else {
|
||||
for (prec = 0; gisdigit((int)c); c = *fmt++) {
|
||||
prec = prec * 10 + (c - '0');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (c == 'h' || c == 'l') {
|
||||
f |= (c == 'h' ? flag_short : flag_long);
|
||||
c = *fmt++;
|
||||
}
|
||||
if (c == 'd' || c == 'i') {
|
||||
long int value;
|
||||
if (f & flag_short) {
|
||||
value = (short int) va_arg(arg, int);
|
||||
} else if (f & flag_long) {
|
||||
value = va_arg(arg, long int);
|
||||
} else {
|
||||
value = va_arg(arg, int);
|
||||
}
|
||||
if (value >= 0) {
|
||||
if (f & flag_plus) {
|
||||
put_ulong(&buf, value, 10, 0, T("+"), width, prec, f);
|
||||
} else if (f & flag_space) {
|
||||
put_ulong(&buf, value, 10, 0, T(" "), width, prec, f);
|
||||
} else {
|
||||
put_ulong(&buf, value, 10, 0, NULL, width, prec, f);
|
||||
}
|
||||
} else {
|
||||
put_ulong(&buf, -value, 10, 0, T("-"), width, prec, f);
|
||||
}
|
||||
} else if (c == 'o' || c == 'u' || c == 'x' || c == 'X') {
|
||||
unsigned long int value;
|
||||
if (f & flag_short) {
|
||||
value = (unsigned short int) va_arg(arg, unsigned int);
|
||||
} else if (f & flag_long) {
|
||||
value = va_arg(arg, unsigned long int);
|
||||
} else {
|
||||
value = va_arg(arg, unsigned int);
|
||||
}
|
||||
if (c == 'o') {
|
||||
if (f & flag_hash && value != 0) {
|
||||
put_ulong(&buf, value, 8, 0, T("0"), width, prec, f);
|
||||
} else {
|
||||
put_ulong(&buf, value, 8, 0, NULL, width, prec, f);
|
||||
}
|
||||
} else if (c == 'u') {
|
||||
put_ulong(&buf, value, 10, 0, NULL, width, prec, f);
|
||||
} else {
|
||||
if (f & flag_hash && value != 0) {
|
||||
if (c == 'x') {
|
||||
put_ulong(&buf, value, 16, 0, T("0x"), width,
|
||||
prec, f);
|
||||
} else {
|
||||
put_ulong(&buf, value, 16, 1, T("0X"), width,
|
||||
prec, f);
|
||||
}
|
||||
} else {
|
||||
/* 04 Apr 02 BgP -- changed so that %X correctly outputs
|
||||
* uppercase hex digits when requested.
|
||||
put_ulong(&buf, value, 16, 0, NULL, width, prec, f);
|
||||
*/
|
||||
put_ulong(&buf, value, 16, ('X' == c) , NULL, width, prec, f);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (c == 'c') {
|
||||
char_t value = va_arg(arg, int);
|
||||
put_char(&buf, value);
|
||||
|
||||
} else if (c == 's' || c == 'S') {
|
||||
char_t *value = va_arg(arg, char_t *);
|
||||
if (value == NULL) {
|
||||
put_string(&buf, T("(null)"), -1, width, prec, f);
|
||||
} else if (f & flag_hash) {
|
||||
put_string(&buf,
|
||||
value + 1, (char_t) *value, width, prec, f);
|
||||
} else {
|
||||
put_string(&buf, value, -1, width, prec, f);
|
||||
}
|
||||
} else if (c == 'p') {
|
||||
void *value = va_arg(arg, void *);
|
||||
put_ulong(&buf,
|
||||
(unsigned long int) value, 16, 0, T("0x"), width, prec, f);
|
||||
} else if (c == 'n') {
|
||||
if (f & flag_short) {
|
||||
short int *value = va_arg(arg, short int *);
|
||||
*value = buf.count;
|
||||
} else if (f & flag_long) {
|
||||
long int *value = va_arg(arg, long int *);
|
||||
*value = buf.count;
|
||||
} else {
|
||||
int *value = va_arg(arg, int *);
|
||||
*value = buf.count;
|
||||
}
|
||||
} else {
|
||||
put_char(&buf, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (buf.s == NULL) {
|
||||
put_char(&buf, '\0');
|
||||
}
|
||||
|
||||
/*
|
||||
* If the user requested a dynamic buffer (*s == NULL), ensure it is returned.
|
||||
*/
|
||||
if (*s == NULL || msize != 0) {
|
||||
*s = buf.s;
|
||||
}
|
||||
|
||||
if (*s != NULL && size > 0) {
|
||||
if (buf.count < size) {
|
||||
(*s)[buf.count] = '\0';
|
||||
} else {
|
||||
(*s)[buf.size - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (msize != 0) {
|
||||
return buf.size;
|
||||
}
|
||||
return buf.count;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Return the length of a string limited by a given length
|
||||
*/
|
||||
|
||||
#if !defined(__rtems__)
|
||||
static int strnlen(char_t *s, unsigned int n)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
len = gstrlen(s);
|
||||
return min(len, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Add a character to a string buffer
|
||||
*/
|
||||
|
||||
static void put_char(strbuf_t *buf, char_t c)
|
||||
{
|
||||
if (buf->count >= (buf->size - 1)) {
|
||||
if (! (buf->flags & STR_REALLOC)) {
|
||||
return;
|
||||
}
|
||||
buf->size += STR_INC;
|
||||
if (buf->size > buf->max && buf->size > STR_INC) {
|
||||
/*
|
||||
* Caller should increase the size of the calling buffer
|
||||
*/
|
||||
buf->size -= STR_INC;
|
||||
return;
|
||||
}
|
||||
if (buf->s == NULL) {
|
||||
buf->s = balloc(B_L, buf->size * sizeof(char_t));
|
||||
} else {
|
||||
buf->s = brealloc(B_L, buf->s, buf->size * sizeof(char_t));
|
||||
}
|
||||
}
|
||||
buf->s[buf->count] = c;
|
||||
if (c != '\0') {
|
||||
++buf->count;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Add a string to a string buffer
|
||||
*/
|
||||
|
||||
static void put_string(strbuf_t *buf, char_t *s, int len, int width,
|
||||
int prec, enum flag f)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (len < 0) {
|
||||
len = strnlen(s, prec >= 0 ? prec : ULONG_MAX);
|
||||
} else if (prec >= 0 && prec < len) {
|
||||
len = prec;
|
||||
}
|
||||
if (width > len && !(f & flag_minus)) {
|
||||
for (i = len; i < width; ++i) {
|
||||
put_char(buf, ' ');
|
||||
}
|
||||
}
|
||||
for (i = 0; i < len; ++i) {
|
||||
put_char(buf, s[i]);
|
||||
}
|
||||
if (width > len && f & flag_minus) {
|
||||
for (i = len; i < width; ++i) {
|
||||
put_char(buf, ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Add a long to a string buffer
|
||||
*/
|
||||
|
||||
static void put_ulong(strbuf_t *buf, unsigned long int value, int base,
|
||||
int upper, char_t *prefix, int width, int prec, enum flag f)
|
||||
{
|
||||
unsigned long x, x2;
|
||||
int len, zeros, i;
|
||||
|
||||
for (len = 1, x = 1; x < ULONG_MAX / base; ++len, x = x2) {
|
||||
x2 = x * base;
|
||||
if (x2 > value) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
zeros = (prec > len) ? prec - len : 0;
|
||||
width -= zeros + len;
|
||||
if (prefix != NULL) {
|
||||
width -= strnlen(prefix, ULONG_MAX);
|
||||
}
|
||||
if (!(f & flag_minus)) {
|
||||
if (f & flag_zero) {
|
||||
for (i = 0; i < width; ++i) {
|
||||
put_char(buf, '0');
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < width; ++i) {
|
||||
put_char(buf, ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (prefix != NULL) {
|
||||
put_string(buf, prefix, -1, 0, -1, flag_none);
|
||||
}
|
||||
for (i = 0; i < zeros; ++i) {
|
||||
put_char(buf, '0');
|
||||
}
|
||||
for ( ; x > 0; x /= base) {
|
||||
int digit = (value / x) % base;
|
||||
put_char(buf, (char) ((digit < 10 ? '0' : (upper ? 'A' : 'a') - 10) +
|
||||
digit));
|
||||
}
|
||||
if (f & flag_minus) {
|
||||
for (i = 0; i < width; ++i) {
|
||||
put_char(buf, ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Convert an ansi string to a unicode string. On an error, we return the
|
||||
* original ansi string which is better than returning NULL. nBytes is the
|
||||
* size of the destination buffer (ubuf) in _bytes_.
|
||||
*/
|
||||
|
||||
char_t *ascToUni(char_t *ubuf, char *str, int nBytes)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
if (MultiByteToWideChar(CP_ACP, 0, str, nBytes / sizeof(char_t), ubuf,
|
||||
nBytes / sizeof(char_t)) < 0) {
|
||||
return (char_t*) str;
|
||||
}
|
||||
#else
|
||||
strncpy(ubuf, str, nBytes);
|
||||
#endif
|
||||
return ubuf;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Convert a unicode string to an ansi string. On an error, return the
|
||||
* original unicode string which is better than returning NULL.
|
||||
* N.B. nBytes is the number of _bytes_ in the destination buffer, buf.
|
||||
*/
|
||||
|
||||
char *uniToAsc(char *buf, char_t *ustr, int nBytes)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
if (WideCharToMultiByte(CP_ACP, 0, ustr, nBytes, buf, nBytes, NULL,
|
||||
NULL) < 0) {
|
||||
return (char*) ustr;
|
||||
}
|
||||
#else
|
||||
strncpy(buf, ustr, nBytes);
|
||||
#endif
|
||||
return (char*) buf;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* allocate (balloc) a buffer and do ascii to unicode conversion into it.
|
||||
* cp points to the ascii buffer. alen is the length of the buffer to be
|
||||
* converted not including a terminating NULL. Return a pointer to the
|
||||
* unicode buffer which must be bfree'd later. Return NULL on failure to
|
||||
* get buffer. The buffer returned is NULL terminated.
|
||||
*/
|
||||
|
||||
char_t *ballocAscToUni(char *cp, int alen)
|
||||
{
|
||||
char_t *unip;
|
||||
int ulen;
|
||||
|
||||
ulen = (alen + 1) * sizeof(char_t);
|
||||
if ((unip = balloc(B_L, ulen)) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ascToUni(unip, cp, ulen);
|
||||
unip[alen] = 0;
|
||||
return unip;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* allocate (balloc) a buffer and do unicode to ascii conversion into it.
|
||||
* unip points to the unicoded string. ulen is the number of characters
|
||||
* in the unicode string not including a teminating null. Return a pointer
|
||||
* to the ascii buffer which must be bfree'd later. Return NULL on failure
|
||||
* to get buffer. The buffer returned is NULL terminated.
|
||||
*/
|
||||
|
||||
char *ballocUniToAsc(char_t *unip, int ulen)
|
||||
{
|
||||
char * cp;
|
||||
|
||||
if ((cp = balloc(B_L, ulen+1)) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
uniToAsc(cp, unip, ulen);
|
||||
cp[ulen] = '\0';
|
||||
return cp;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* convert a hex string to an integer. The end of the string or a non-hex
|
||||
* character will indicate the end of the hex specification.
|
||||
*/
|
||||
|
||||
unsigned int hextoi(char_t *hexstring)
|
||||
{
|
||||
register char_t *h;
|
||||
register unsigned int c, v;
|
||||
|
||||
v = 0;
|
||||
h = hexstring;
|
||||
if (*h == '0' && (*(h+1) == 'x' || *(h+1) == 'X')) {
|
||||
h += 2;
|
||||
}
|
||||
while ((c = (unsigned int)*h++) != 0) {
|
||||
if (c >= '0' && c <= '9') {
|
||||
c -= '0';
|
||||
} else if (c >= 'a' && c <= 'f') {
|
||||
c = (c - 'a') + 10;
|
||||
} else if (c >= 'A' && c <= 'F') {
|
||||
c = (c - 'A') + 10;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
v = (v * 0x10) + c;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* convert a string to an integer. If the string starts with "0x" or "0X"
|
||||
* a hexidecimal conversion is done.
|
||||
*/
|
||||
|
||||
unsigned int gstrtoi(char_t *s)
|
||||
{
|
||||
if (*s == '0' && (*(s+1) == 'x' || *(s+1) == 'X')) {
|
||||
s += 2;
|
||||
return hextoi(s);
|
||||
}
|
||||
return gatoi(s);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,584 +0,0 @@
|
||||
/*
|
||||
* ringq.c -- Ring queue buffering module
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* A ring queue allows maximum utilization of memory for data storage and is
|
||||
* ideal for input/output buffering. This module provides a highly efficient
|
||||
* implementation and a vehicle for dynamic strings.
|
||||
*
|
||||
* WARNING: This is a public implementation and callers have full access to
|
||||
* the queue structure and pointers. Change this module very carefully.
|
||||
*
|
||||
* This module follows the open/close model.
|
||||
*
|
||||
* Operation of a ringq where rq is a pointer to a ringq :
|
||||
*
|
||||
* rq->buflen contains the size of the buffer.
|
||||
* rq->buf will point to the start of the buffer.
|
||||
* rq->servp will point to the first (un-consumed) data byte.
|
||||
* rq->endp will point to the next free location to which new data is added
|
||||
* rq->endbuf will point to one past the end of the buffer.
|
||||
*
|
||||
* Eg. If the ringq contains the data "abcdef", it might look like :
|
||||
*
|
||||
* +-------------------------------------------------------------------+
|
||||
* | | | | | | | | a | b | c | d | e | f | | | | |
|
||||
* +-------------------------------------------------------------------+
|
||||
* ^ ^ ^ ^
|
||||
* | | | |
|
||||
* rq->buf rq->servp rq->endp rq->enduf
|
||||
*
|
||||
* The queue is empty when servp == endp. This means that the queue will hold
|
||||
* at most rq->buflen -1 bytes. It is the filler's responsibility to ensure
|
||||
* the ringq is never filled such that servp == endp.
|
||||
*
|
||||
* It is the filler's responsibility to "wrap" the endp back to point to
|
||||
* rq->buf when the pointer steps past the end. Correspondingly it is the
|
||||
* consumers responsibility to "wrap" the servp when it steps to rq->endbuf.
|
||||
* The ringqPutc and ringqGetc routines will do this automatically.
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#ifdef UEMF
|
||||
#include "uemf.h"
|
||||
#else
|
||||
#include "basic/basicInternal.h"
|
||||
#endif
|
||||
|
||||
/*********************************** Defines **********************************/
|
||||
/*
|
||||
* Faster than a function call
|
||||
*/
|
||||
|
||||
#define RINGQ_LEN(rq) \
|
||||
((rq->servp > rq->endp) ? \
|
||||
(rq->buflen + (rq->endp - rq->servp)) : \
|
||||
(rq->endp - rq->servp))
|
||||
|
||||
/***************************** Forward Declarations ***************************/
|
||||
|
||||
static int ringqGrow(ringq_t *rq);
|
||||
static int getBinBlockSize(int size);
|
||||
|
||||
int ringqGrowCalls = 0;
|
||||
|
||||
/*********************************** Code *************************************/
|
||||
/*
|
||||
* Create a new ringq. "increment" is the amount to increase the size of the
|
||||
* ringq should it need to grow to accomodate data being added. "maxsize" is
|
||||
* an upper limit (sanity level) beyond which the q must not grow. Set maxsize
|
||||
* to -1 to imply no upper limit. The buffer for the ringq is always
|
||||
* dynamically allocated. Set maxsize
|
||||
*/
|
||||
|
||||
int ringqOpen(ringq_t *rq, int initSize, int maxsize)
|
||||
{
|
||||
int increment;
|
||||
|
||||
a_assert(rq);
|
||||
a_assert(initSize >= 0);
|
||||
|
||||
increment = getBinBlockSize(initSize);
|
||||
if ((rq->buf = balloc(B_L, (increment))) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
rq->maxsize = maxsize;
|
||||
rq->buflen = increment;
|
||||
rq->increment = increment;
|
||||
rq->endbuf = &rq->buf[rq->buflen];
|
||||
rq->servp = rq->buf;
|
||||
rq->endp = rq->buf;
|
||||
*rq->servp = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Delete a ringq and free the ringq buffer.
|
||||
*/
|
||||
|
||||
void ringqClose(ringq_t *rq)
|
||||
{
|
||||
a_assert(rq);
|
||||
a_assert(rq->buflen == (rq->endbuf - rq->buf));
|
||||
|
||||
if (rq == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ringqFlush(rq);
|
||||
bfree(B_L, (char*) rq->buf);
|
||||
rq->buf = NULL;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Return the length of the data in the ringq. Users must fill the queue to
|
||||
* a high water mark of at most one less than the queue size.
|
||||
*/
|
||||
|
||||
int ringqLen(ringq_t *rq)
|
||||
{
|
||||
a_assert(rq);
|
||||
a_assert(rq->buflen == (rq->endbuf - rq->buf));
|
||||
|
||||
if (rq->servp > rq->endp) {
|
||||
return rq->buflen + rq->endp - rq->servp;
|
||||
} else {
|
||||
return rq->endp - rq->servp;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Get a byte from the queue
|
||||
*/
|
||||
|
||||
int ringqGetc(ringq_t *rq)
|
||||
{
|
||||
char_t c;
|
||||
char_t* cp;
|
||||
|
||||
a_assert(rq);
|
||||
a_assert(rq->buflen == (rq->endbuf - rq->buf));
|
||||
|
||||
if (rq->servp == rq->endp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cp = (char_t*) rq->servp;
|
||||
c = *cp++;
|
||||
rq->servp = (unsigned char *) cp;
|
||||
if (rq->servp >= rq->endbuf) {
|
||||
rq->servp = rq->buf;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Add a char to the queue. Note if being used to store wide strings
|
||||
* this does not add a trailing '\0'. Grow the q as required.
|
||||
*/
|
||||
|
||||
int ringqPutc(ringq_t *rq, char_t c)
|
||||
{
|
||||
char_t *cp;
|
||||
|
||||
a_assert(rq);
|
||||
a_assert(rq->buflen == (rq->endbuf - rq->buf));
|
||||
|
||||
if ((ringqPutBlkMax(rq) < (int) sizeof(char_t)) && !ringqGrow(rq)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cp = (char_t*) rq->endp;
|
||||
*cp++ = (char_t) c;
|
||||
rq->endp = (unsigned char *) cp;
|
||||
if (rq->endp >= rq->endbuf) {
|
||||
rq->endp = rq->buf;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Insert a wide character at the front of the queue
|
||||
*/
|
||||
|
||||
int ringqInsertc(ringq_t *rq, char_t c)
|
||||
{
|
||||
char_t *cp;
|
||||
|
||||
a_assert(rq);
|
||||
a_assert(rq->buflen == (rq->endbuf - rq->buf));
|
||||
|
||||
if (ringqPutBlkMax(rq) < (int) sizeof(char_t) && !ringqGrow(rq)) {
|
||||
return -1;
|
||||
}
|
||||
if (rq->servp <= rq->buf) {
|
||||
rq->servp = rq->endbuf;
|
||||
}
|
||||
cp = (char_t*) rq->servp;
|
||||
*--cp = (char_t) c;
|
||||
rq->servp = (unsigned char *) cp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Add a string to the queue. Add a trailing null (maybe two nulls)
|
||||
*/
|
||||
|
||||
int ringqPutStr(ringq_t *rq, char_t *str)
|
||||
{
|
||||
int rc;
|
||||
|
||||
a_assert(rq);
|
||||
a_assert(str);
|
||||
a_assert(rq->buflen == (rq->endbuf - rq->buf));
|
||||
|
||||
rc = ringqPutBlk(rq, (unsigned char*) str, gstrlen(str) * sizeof(char_t));
|
||||
*((char_t*) rq->endp) = (char_t) '\0';
|
||||
return rc;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Add a null terminator. This does NOT increase the size of the queue
|
||||
*/
|
||||
|
||||
void ringqAddNull(ringq_t *rq)
|
||||
{
|
||||
a_assert(rq);
|
||||
a_assert(rq->buflen == (rq->endbuf - rq->buf));
|
||||
|
||||
*((char_t*) rq->endp) = (char_t) '\0';
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
#ifdef UNICODE
|
||||
/*
|
||||
* Get a byte from the queue
|
||||
*/
|
||||
|
||||
int ringqGetcA(ringq_t *rq)
|
||||
{
|
||||
unsigned char c;
|
||||
|
||||
a_assert(rq);
|
||||
a_assert(rq->buflen == (rq->endbuf - rq->buf));
|
||||
|
||||
if (rq->servp == rq->endp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
c = *rq->servp++;
|
||||
if (rq->servp >= rq->endbuf) {
|
||||
rq->servp = rq->buf;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Add a byte to the queue. Note if being used to store strings this does not
|
||||
* add a trailing '\0'. Grow the q as required.
|
||||
*/
|
||||
|
||||
int ringqPutcA(ringq_t *rq, char c)
|
||||
{
|
||||
a_assert(rq);
|
||||
a_assert(rq->buflen == (rq->endbuf - rq->buf));
|
||||
|
||||
if (ringqPutBlkMax(rq) == 0 && !ringqGrow(rq)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*rq->endp++ = (unsigned char) c;
|
||||
if (rq->endp >= rq->endbuf) {
|
||||
rq->endp = rq->buf;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Insert a byte at the front of the queue
|
||||
*/
|
||||
|
||||
int ringqInsertcA(ringq_t *rq, char c)
|
||||
{
|
||||
a_assert(rq);
|
||||
a_assert(rq->buflen == (rq->endbuf - rq->buf));
|
||||
|
||||
if (ringqPutBlkMax(rq) == 0 && !ringqGrow(rq)) {
|
||||
return -1;
|
||||
}
|
||||
if (rq->servp <= rq->buf) {
|
||||
rq->servp = rq->endbuf;
|
||||
}
|
||||
*--rq->servp = (unsigned char) c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Add a string to the queue. Add a trailing null (not really in the q).
|
||||
* ie. beyond the last valid byte.
|
||||
*/
|
||||
|
||||
int ringqPutStrA(ringq_t *rq, char *str)
|
||||
{
|
||||
int rc;
|
||||
|
||||
a_assert(rq);
|
||||
a_assert(str);
|
||||
a_assert(rq->buflen == (rq->endbuf - rq->buf));
|
||||
|
||||
rc = ringqPutBlk(rq, (unsigned char*) str, strlen(str));
|
||||
rq->endp[0] = '\0';
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* UNICODE */
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Add a block of data to the ringq. Return the number of bytes added.
|
||||
* Grow the q as required.
|
||||
*/
|
||||
|
||||
int ringqPutBlk(ringq_t *rq, unsigned char *buf, int size)
|
||||
{
|
||||
int this, bytes_put;
|
||||
|
||||
a_assert(rq);
|
||||
a_assert(rq->buflen == (rq->endbuf - rq->buf));
|
||||
a_assert(buf);
|
||||
a_assert(0 <= size);
|
||||
|
||||
/*
|
||||
* Loop adding the maximum bytes we can add in a single straight line copy
|
||||
*/
|
||||
bytes_put = 0;
|
||||
while (size > 0) {
|
||||
this = min(ringqPutBlkMax(rq), size);
|
||||
if (this <= 0) {
|
||||
if (! ringqGrow(rq)) {
|
||||
break;
|
||||
}
|
||||
this = min(ringqPutBlkMax(rq), size);
|
||||
}
|
||||
|
||||
memcpy(rq->endp, buf, this);
|
||||
buf += this;
|
||||
rq->endp += this;
|
||||
size -= this;
|
||||
bytes_put += this;
|
||||
|
||||
if (rq->endp >= rq->endbuf) {
|
||||
rq->endp = rq->buf;
|
||||
}
|
||||
}
|
||||
return bytes_put;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Get a block of data from the ringq. Return the number of bytes returned.
|
||||
*/
|
||||
|
||||
int ringqGetBlk(ringq_t *rq, unsigned char *buf, int size)
|
||||
{
|
||||
int this, bytes_read;
|
||||
|
||||
a_assert(rq);
|
||||
a_assert(rq->buflen == (rq->endbuf - rq->buf));
|
||||
a_assert(buf);
|
||||
a_assert(0 <= size && size < rq->buflen);
|
||||
|
||||
/*
|
||||
* Loop getting the maximum bytes we can get in a single straight line copy
|
||||
*/
|
||||
bytes_read = 0;
|
||||
while (size > 0) {
|
||||
this = ringqGetBlkMax(rq);
|
||||
this = min(this, size);
|
||||
if (this <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(buf, rq->servp, this);
|
||||
buf += this;
|
||||
rq->servp += this;
|
||||
size -= this;
|
||||
bytes_read += this;
|
||||
|
||||
if (rq->servp >= rq->endbuf) {
|
||||
rq->servp = rq->buf;
|
||||
}
|
||||
}
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Return the maximum number of bytes the ring q can accept via a single
|
||||
* block copy. Useful if the user is doing their own data insertion.
|
||||
*/
|
||||
|
||||
int ringqPutBlkMax(ringq_t *rq)
|
||||
{
|
||||
int space, in_a_line;
|
||||
|
||||
a_assert(rq);
|
||||
a_assert(rq->buflen == (rq->endbuf - rq->buf));
|
||||
|
||||
space = rq->buflen - RINGQ_LEN(rq) - 1;
|
||||
in_a_line = rq->endbuf - rq->endp;
|
||||
|
||||
return min(in_a_line, space);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Return the maximum number of bytes the ring q can provide via a single
|
||||
* block copy. Useful if the user is doing their own data retrieval.
|
||||
*/
|
||||
|
||||
int ringqGetBlkMax(ringq_t *rq)
|
||||
{
|
||||
int len, in_a_line;
|
||||
|
||||
a_assert(rq);
|
||||
a_assert(rq->buflen == (rq->endbuf - rq->buf));
|
||||
|
||||
len = RINGQ_LEN(rq);
|
||||
in_a_line = rq->endbuf - rq->servp;
|
||||
|
||||
return min(in_a_line, len);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Adjust the endp pointer after the user has copied data into the queue.
|
||||
*/
|
||||
|
||||
void ringqPutBlkAdj(ringq_t *rq, int size)
|
||||
{
|
||||
a_assert(rq);
|
||||
a_assert(rq->buflen == (rq->endbuf - rq->buf));
|
||||
a_assert(0 <= size && size < rq->buflen);
|
||||
|
||||
rq->endp += size;
|
||||
if (rq->endp >= rq->endbuf) {
|
||||
rq->endp -= rq->buflen;
|
||||
}
|
||||
/*
|
||||
* Flush the queue if the endp pointer is corrupted via a bad size
|
||||
*/
|
||||
if (rq->endp >= rq->endbuf) {
|
||||
error(E_L, E_LOG, T("Bad end pointer"));
|
||||
ringqFlush(rq);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Adjust the servp pointer after the user has copied data from the queue.
|
||||
*/
|
||||
|
||||
void ringqGetBlkAdj(ringq_t *rq, int size)
|
||||
{
|
||||
a_assert(rq);
|
||||
a_assert(rq->buflen == (rq->endbuf - rq->buf));
|
||||
a_assert(0 < size && size < rq->buflen);
|
||||
|
||||
rq->servp += size;
|
||||
if (rq->servp >= rq->endbuf) {
|
||||
rq->servp -= rq->buflen;
|
||||
}
|
||||
/*
|
||||
* Flush the queue if the servp pointer is corrupted via a bad size
|
||||
*/
|
||||
if (rq->servp >= rq->endbuf) {
|
||||
error(E_L, E_LOG, T("Bad serv pointer"));
|
||||
ringqFlush(rq);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Flush all data in a ring q. Reset the pointers.
|
||||
*/
|
||||
|
||||
void ringqFlush(ringq_t *rq)
|
||||
{
|
||||
a_assert(rq);
|
||||
a_assert(rq->servp);
|
||||
|
||||
rq->servp = rq->buf;
|
||||
rq->endp = rq->buf;
|
||||
if (rq->servp) {
|
||||
*rq->servp = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Grow the buffer. Return true if the buffer can be grown. Grow using
|
||||
* the increment size specified when opening the ringq. Don't grow beyond
|
||||
* the maximum possible size.
|
||||
*/
|
||||
|
||||
static int ringqGrow(ringq_t *rq)
|
||||
{
|
||||
unsigned char *newbuf;
|
||||
int len;
|
||||
|
||||
a_assert(rq);
|
||||
|
||||
if (rq->maxsize >= 0 && rq->buflen >= rq->maxsize) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = ringqLen(rq);
|
||||
|
||||
if ((newbuf = balloc(B_L, rq->buflen + rq->increment)) == NULL) {
|
||||
return 0;
|
||||
}
|
||||
ringqGetBlk(rq, newbuf, ringqLen(rq));
|
||||
bfree(B_L, (char*) rq->buf);
|
||||
|
||||
#ifdef OLD
|
||||
rq->endp = &newbuf[endp];
|
||||
rq->servp = &newbuf[servp];
|
||||
rq->endbuf = &newbuf[rq->buflen];
|
||||
rq->buf = newbuf;
|
||||
#endif
|
||||
|
||||
rq->buflen += rq->increment;
|
||||
rq->endp = newbuf;
|
||||
rq->servp = newbuf;
|
||||
rq->buf = newbuf;
|
||||
rq->endbuf = &rq->buf[rq->buflen];
|
||||
|
||||
ringqPutBlk(rq, newbuf, len);
|
||||
|
||||
/*
|
||||
* Double the increment so the next grow will line up with balloc'ed memory
|
||||
*/
|
||||
rq->increment = getBinBlockSize(2 * rq->increment);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Find the smallest binary memory size that "size" will fit into. This
|
||||
* makes the ringq and ringqGrow routines much more efficient. The balloc
|
||||
* routine likes powers of 2 minus 1.
|
||||
*/
|
||||
|
||||
static int getBinBlockSize(int size)
|
||||
{
|
||||
int q;
|
||||
|
||||
size = size >> B_SHIFT;
|
||||
for (q = 0; size; size >>= 1) {
|
||||
q++;
|
||||
}
|
||||
return (1 << (B_SHIFT + q));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,193 +0,0 @@
|
||||
/*
|
||||
* rom.c -- Support for ROMed page retrieval.
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* This module provides web page retrieval from compiled web pages. Use the
|
||||
* webcomp program to compile web pages and link into the GoAhead WebServer.
|
||||
* This module uses a hashed symbol table for fast page lookup.
|
||||
*
|
||||
* Usage: webcomp -f webPageFileList -p Prefix >webrom.c
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "wsIntrn.h"
|
||||
|
||||
/******************************** Local Data **********************************/
|
||||
|
||||
#ifdef WEBS_PAGE_ROM
|
||||
|
||||
sym_fd_t romTab; /* Symbol table for web pages */
|
||||
|
||||
/*********************************** Code *************************************/
|
||||
/*
|
||||
* Open the ROM module
|
||||
*/
|
||||
|
||||
int websRomOpen()
|
||||
{
|
||||
websRomPageIndexType *wip;
|
||||
int nchars;
|
||||
char_t name[SYM_MAX];
|
||||
|
||||
romTab = symOpen(WEBS_SYM_INIT);
|
||||
|
||||
for (wip = websRomPageIndex; wip->path; wip++) {
|
||||
gstrncpy(name, wip->path, SYM_MAX);
|
||||
nchars = gstrlen(name) - 1;
|
||||
if (nchars > 0 &&
|
||||
(name[nchars] == '/' || name[nchars] == '\\')) {
|
||||
name[nchars] = '\0';
|
||||
}
|
||||
symEnter(romTab, name, valueInteger((int) wip), 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Close the ROM module
|
||||
*/
|
||||
|
||||
void websRomClose()
|
||||
{
|
||||
symClose(romTab);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Open a web page
|
||||
*/
|
||||
|
||||
int websRomPageOpen(webs_t wp, char_t *path, int mode, int perm)
|
||||
{
|
||||
websRomPageIndexType *wip;
|
||||
sym_t *sp;
|
||||
|
||||
a_assert(websValid(wp));
|
||||
a_assert(path && *path);
|
||||
|
||||
if ((sp = symLookup(romTab, path)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
wip = (websRomPageIndexType*) sp->content.value.integer;
|
||||
wip->pos = 0;
|
||||
return (wp->docfd = wip - websRomPageIndex);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Close a web page
|
||||
*/
|
||||
|
||||
void websRomPageClose(int fd)
|
||||
{
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Stat a web page
|
||||
*/
|
||||
|
||||
int websRomPageStat(char_t *path, websStatType *sbuf)
|
||||
{
|
||||
websRomPageIndexType *wip;
|
||||
sym_t *sp;
|
||||
|
||||
a_assert(path && *path);
|
||||
|
||||
if ((sp = symLookup(romTab, path)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
wip = (websRomPageIndexType*) sp->content.value.integer;
|
||||
|
||||
memset(sbuf, 0, sizeof(websStatType));
|
||||
sbuf->size = wip->size;
|
||||
if (wip->page == NULL) {
|
||||
sbuf->isDir = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Read a web page
|
||||
*/
|
||||
|
||||
int websRomPageReadData(webs_t wp, char *buf, int nBytes)
|
||||
{
|
||||
websRomPageIndexType *wip;
|
||||
int len;
|
||||
|
||||
a_assert(websValid(wp));
|
||||
a_assert(buf);
|
||||
a_assert(wp->docfd >= 0);
|
||||
|
||||
wip = &websRomPageIndex[wp->docfd];
|
||||
|
||||
len = min(wip->size - wip->pos, nBytes);
|
||||
memcpy(buf, &wip->page[wip->pos], len);
|
||||
wip->pos += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Position a web page
|
||||
*/
|
||||
|
||||
long websRomPageSeek(webs_t wp, long offset, int origin)
|
||||
{
|
||||
websRomPageIndexType *wip;
|
||||
long pos;
|
||||
|
||||
a_assert(websValid(wp));
|
||||
a_assert(origin == SEEK_SET || origin == SEEK_CUR || origin == SEEK_END);
|
||||
a_assert(wp->docfd >= 0);
|
||||
|
||||
wip = &websRomPageIndex[wp->docfd];
|
||||
|
||||
if (origin != SEEK_SET && origin != SEEK_CUR && origin != SEEK_END) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wp->docfd < 0) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
pos = offset;
|
||||
switch (origin) {
|
||||
case SEEK_CUR:
|
||||
pos = wip->pos + offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
pos = wip->size + offset;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (pos < 0) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (wip->pos = pos);
|
||||
}
|
||||
|
||||
#endif /* WEBS_PAGE_ROM */
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,6 +0,0 @@
|
||||
/*
|
||||
* rtems_webserver.h --
|
||||
*
|
||||
*/
|
||||
|
||||
int rtems_initialize_webserver();
|
||||
@@ -1,235 +0,0 @@
|
||||
/*
|
||||
* security.c -- Security handler
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* This module provides a basic security policy.
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#include "wsIntrn.h"
|
||||
#include "um.h"
|
||||
#ifdef DIGEST_ACCESS_SUPPORT
|
||||
#include "websda.h"
|
||||
#endif
|
||||
|
||||
/********************************** Defines ***********************************/
|
||||
/*
|
||||
* The following #defines change the behaviour of security in the absence
|
||||
* of User Management.
|
||||
* Note that use of User management functions require prior calling of
|
||||
* umInit() to behave correctly
|
||||
*/
|
||||
|
||||
#ifndef USER_MANAGEMENT_SUPPORT
|
||||
#define umGetAccessMethodForURL(url) AM_FULL
|
||||
#define umUserExists(userid) 0
|
||||
#define umUserCanAccessURL(userid, url) 1
|
||||
#define umGetUserPassword(userid) websGetPassword()
|
||||
#define umGetAccessLimitSecure(accessLimit) 0
|
||||
#define umGetAccessLimit(url) NULL
|
||||
#endif
|
||||
|
||||
/******************************** Local Data **********************************/
|
||||
|
||||
static char_t websPassword[WEBS_MAX_PASS]; /* Access password (decoded) */
|
||||
#ifdef _DEBUG
|
||||
static int debugSecurity = 1;
|
||||
#else
|
||||
static int debugSecurity = 0;
|
||||
#endif
|
||||
|
||||
/*********************************** Code *************************************/
|
||||
/*
|
||||
* Determine if this request should be honored
|
||||
*/
|
||||
|
||||
int websSecurityHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg,
|
||||
char_t *url, char_t *path, char_t *query)
|
||||
{
|
||||
char_t *type, *userid, *password, *accessLimit;
|
||||
int flags, nRet;
|
||||
accessMeth_t am;
|
||||
|
||||
a_assert(websValid(wp));
|
||||
a_assert(url && *url);
|
||||
a_assert(path && *path);
|
||||
/*
|
||||
* Get the critical request details
|
||||
*/
|
||||
type = websGetRequestType(wp);
|
||||
password = websGetRequestPassword(wp);
|
||||
userid = websGetRequestUserName(wp);
|
||||
flags = websGetRequestFlags(wp);
|
||||
/*
|
||||
* Get the access limit for the URL. Exit if none found.
|
||||
*/
|
||||
accessLimit = umGetAccessLimit(path);
|
||||
if (accessLimit == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if URL must be encrypted
|
||||
*/
|
||||
#ifdef WEBS_SSL_SUPPORT
|
||||
nRet = umGetAccessLimitSecure(accessLimit);
|
||||
if (nRet && ((flags & WEBS_SECURE) == 0)) {
|
||||
websStats.access++;
|
||||
websError(wp, 405, T("Access Denied\nSecure access is required."));
|
||||
trace(3, T("SEC: Non-secure access attempted on <%s>\n"), path);
|
||||
/* bugfix 5/24/02 -- we were leaking the memory pointed to by
|
||||
* 'accessLimit'. Thanks to Simon Byholm.
|
||||
*/
|
||||
bfree(B_L, accessLimit);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Get the access limit for the URL
|
||||
*/
|
||||
am = umGetAccessMethodForURL(accessLimit);
|
||||
|
||||
nRet = 0;
|
||||
if ((flags & WEBS_LOCAL_REQUEST) && (debugSecurity == 0)) {
|
||||
/*
|
||||
* Local access is always allowed (defeat when debugging)
|
||||
*/
|
||||
} else if (am == AM_NONE) {
|
||||
/*
|
||||
* URL is supposed to be hidden! Make like it wasn't found.
|
||||
*/
|
||||
websStats.access++;
|
||||
websError(wp, 400, T("Page Not Found"));
|
||||
nRet = 1;
|
||||
} else if (userid && *userid) {
|
||||
if (!umUserExists(userid)) {
|
||||
websStats.access++;
|
||||
websError(wp, 401, T("Access Denied\nUnknown User"));
|
||||
trace(3, T("SEC: Unknown user <%s> attempted to access <%s>\n"),
|
||||
userid, path);
|
||||
nRet = 1;
|
||||
} else if (!umUserCanAccessURL(userid, accessLimit)) {
|
||||
websStats.access++;
|
||||
websError(wp, 403, T("Access Denied\nProhibited User"));
|
||||
nRet = 1;
|
||||
} else if (password && * password) {
|
||||
char_t * userpass = umGetUserPassword(userid);
|
||||
if (userpass) {
|
||||
if (gstrcmp(password, userpass) != 0) {
|
||||
websStats.access++;
|
||||
websError(wp, 401, T("Access Denied\nWrong Password"));
|
||||
trace(3, T("SEC: Password fail for user <%s>")
|
||||
T("attempt to access <%s>\n"), userid, path);
|
||||
nRet = 1;
|
||||
} else {
|
||||
/*
|
||||
* User and password check out.
|
||||
*/
|
||||
}
|
||||
|
||||
bfree (B_L, userpass);
|
||||
}
|
||||
#ifdef DIGEST_ACCESS_SUPPORT
|
||||
} else if (flags & WEBS_AUTH_DIGEST) {
|
||||
|
||||
char_t *digestCalc;
|
||||
|
||||
/*
|
||||
* Check digest for equivalence
|
||||
*/
|
||||
wp->password = umGetUserPassword(userid);
|
||||
|
||||
a_assert(wp->digest);
|
||||
a_assert(wp->nonce);
|
||||
a_assert(wp->password);
|
||||
|
||||
digestCalc = websCalcDigest(wp);
|
||||
a_assert(digestCalc);
|
||||
|
||||
if (gstrcmp(wp->digest, digestCalc) != 0) {
|
||||
websStats.access++;
|
||||
websError(wp, 405, T("Access Denied\nWrong Password"));
|
||||
nRet = 1;
|
||||
}
|
||||
|
||||
bfree (B_L, digestCalc);
|
||||
#endif
|
||||
} else {
|
||||
/*
|
||||
* No password has been specified
|
||||
*/
|
||||
#ifdef DIGEST_ACCESS_SUPPORT
|
||||
if (am == AM_DIGEST) {
|
||||
wp->flags |= WEBS_AUTH_DIGEST;
|
||||
}
|
||||
#endif
|
||||
websStats.errors++;
|
||||
websError(wp, 401,
|
||||
T("Access to this document requires a password"));
|
||||
nRet = 1;
|
||||
}
|
||||
} else if (am != AM_FULL) {
|
||||
/*
|
||||
* This will cause the browser to display a password / username
|
||||
* dialog
|
||||
*/
|
||||
#ifdef DIGEST_ACCESS_SUPPORT
|
||||
if (am == AM_DIGEST) {
|
||||
wp->flags |= WEBS_AUTH_DIGEST;
|
||||
}
|
||||
#endif
|
||||
websStats.errors++;
|
||||
websError(wp, 401, T("Access to this document requires a User ID"));
|
||||
nRet = 1;
|
||||
}
|
||||
|
||||
bfree(B_L, accessLimit);
|
||||
|
||||
return nRet;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Delete the default security handler
|
||||
*/
|
||||
|
||||
void websSecurityDelete()
|
||||
{
|
||||
websUrlHandlerDelete(websSecurityHandler);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Store the new password, expect a decoded password. Store in websPassword in
|
||||
* the decoded form.
|
||||
*/
|
||||
|
||||
void websSetPassword(char_t *password)
|
||||
{
|
||||
a_assert(password);
|
||||
|
||||
gstrncpy(websPassword, password, TSZ(websPassword));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Get password, return the decoded form
|
||||
*/
|
||||
|
||||
char_t *websGetPassword()
|
||||
{
|
||||
return bstrdup(B_L, websPassword);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,791 +0,0 @@
|
||||
/*
|
||||
* sock.c -- Posix Socket upper layer support module for general posix use
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* Posix Socket Module. This supports blocking and non-blocking buffered
|
||||
* socket I/O.
|
||||
*/
|
||||
|
||||
/********************************** Includes **********************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef UEMF
|
||||
#include "uemf.h"
|
||||
#else
|
||||
#include <socket.h>
|
||||
#include <types.h>
|
||||
#include <unistd.h>
|
||||
#include "emfInternal.h"
|
||||
#endif
|
||||
|
||||
/************************************ Locals **********************************/
|
||||
|
||||
socket_t **socketList; /* List of open sockets */
|
||||
int socketMax; /* Maximum size of socket */
|
||||
int socketHighestFd = -1; /* Highest socket fd opened */
|
||||
|
||||
/***************************** Forward Declarations ***************************/
|
||||
|
||||
static int socketDoOutput(socket_t *sp, char *buf, int toWrite, int *errCode);
|
||||
static int tryAlternateSendTo(int sock, char *buf, int toWrite, int i,
|
||||
struct sockaddr *server);
|
||||
|
||||
/*********************************** Code *************************************/
|
||||
/*
|
||||
* Write to a socket. Absorb as much data as the socket can buffer. Block if
|
||||
* the socket is in blocking mode. Returns -1 on error, otherwise the number
|
||||
* of bytes written.
|
||||
*/
|
||||
|
||||
int socketWrite(int sid, char *buf, int bufsize)
|
||||
{
|
||||
socket_t *sp;
|
||||
ringq_t *rq;
|
||||
int len, bytesWritten, room;
|
||||
|
||||
a_assert(buf);
|
||||
a_assert(bufsize >= 0);
|
||||
|
||||
if ((sp = socketPtr(sid)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop adding as much data to the output ringq as we can absorb. Initiate a
|
||||
* flush when the ringq is too full and continue. Block in socketFlush if the
|
||||
* socket is in blocking mode.
|
||||
*/
|
||||
rq = &sp->outBuf;
|
||||
for (bytesWritten = 0; bufsize > 0; ) {
|
||||
if ((room = ringqPutBlkMax(rq)) == 0) {
|
||||
if (socketFlush(sid) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if ((room = ringqPutBlkMax(rq)) == 0) {
|
||||
if (sp->flags & SOCKET_BLOCK) {
|
||||
#if (defined (WIN) || defined (CE))
|
||||
int errCode;
|
||||
if (! socketWaitForEvent(sp, FD_WRITE | SOCKET_WRITABLE,
|
||||
&errCode)) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
len = min(room, bufsize);
|
||||
ringqPutBlk(rq, (unsigned char *) buf, len);
|
||||
bytesWritten += len;
|
||||
bufsize -= len;
|
||||
buf += len;
|
||||
}
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Write a string to a socket
|
||||
*/
|
||||
|
||||
int socketWriteString(int sid, char_t *buf)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
char *byteBuf;
|
||||
int r, len;
|
||||
|
||||
len = gstrlen(buf);
|
||||
byteBuf = ballocUniToAsc(buf, len);
|
||||
r = socketWrite(sid, byteBuf, len);
|
||||
bfreeSafe(B_L, byteBuf);
|
||||
return r;
|
||||
#else
|
||||
return socketWrite(sid, buf, strlen(buf));
|
||||
#endif /* UNICODE */
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Read from a socket. Return the number of bytes read if successful. This
|
||||
* may be less than the requested "bufsize" and may be zero. Return -1 for
|
||||
* errors. Return 0 for EOF. Otherwise return the number of bytes read.
|
||||
* If this routine returns zero it indicates an EOF condition.
|
||||
* which can be verified with socketEof()
|
||||
|
||||
* Note: this ignores the line buffer, so a previous socketGets
|
||||
* which read a partial line may cause a subsequent socketRead to miss some
|
||||
* data. This routine may block if the socket is in blocking mode.
|
||||
*
|
||||
*/
|
||||
|
||||
int socketRead(int sid, char *buf, int bufsize)
|
||||
{
|
||||
socket_t *sp;
|
||||
ringq_t *rq;
|
||||
int len, room, errCode, bytesRead;
|
||||
|
||||
a_assert(buf);
|
||||
a_assert(bufsize > 0);
|
||||
|
||||
if ((sp = socketPtr(sid)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sp->flags & SOCKET_EOF) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rq = &sp->inBuf;
|
||||
for (bytesRead = 0; bufsize > 0; ) {
|
||||
len = min(ringqLen(rq), bufsize);
|
||||
if (len <= 0) {
|
||||
/*
|
||||
* if blocking mode and already have data, exit now or it may block
|
||||
* forever.
|
||||
*/
|
||||
if ((sp->flags & SOCKET_BLOCK) &&
|
||||
(bytesRead > 0)) {
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* This flush is critical for readers of datagram packets. If the
|
||||
* buffer is not big enough to read the whole datagram in one hit,
|
||||
* the recvfrom call will fail.
|
||||
*/
|
||||
ringqFlush(rq);
|
||||
room = ringqPutBlkMax(rq);
|
||||
len = socketGetInput(sid, (char *) rq->endp, room, &errCode);
|
||||
if (len < 0) {
|
||||
if (errCode == EWOULDBLOCK) {
|
||||
if ((sp->flags & SOCKET_BLOCK) &&
|
||||
(bytesRead == 0)) {
|
||||
continue;
|
||||
}
|
||||
if (bytesRead >= 0) {
|
||||
return bytesRead;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
|
||||
} else if (len == 0) {
|
||||
/*
|
||||
* If bytesRead is 0, this is EOF since socketRead should never
|
||||
* be called unless there is data yet to be read. Set the flag.
|
||||
* Then pass back the number of bytes read.
|
||||
*/
|
||||
if (bytesRead == 0) {
|
||||
sp->flags |= SOCKET_EOF;
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
ringqPutBlkAdj(rq, len);
|
||||
len = min(len, bufsize);
|
||||
}
|
||||
memcpy(&buf[bytesRead], rq->servp, len);
|
||||
ringqGetBlkAdj(rq, len);
|
||||
bufsize -= len;
|
||||
bytesRead += len;
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Get a string from a socket. This returns data in *buf in a malloced string
|
||||
* after trimming the '\n'. If there is zero bytes returned, *buf will be set
|
||||
* to NULL. If doing non-blocking I/O, it returns -1 for error, EOF or when
|
||||
* no complete line yet read. If doing blocking I/O, it will block until an
|
||||
* entire line is read. If a partial line is read socketInputBuffered or
|
||||
* socketEof can be used to distinguish between EOF and partial line still
|
||||
* buffered. This routine eats and ignores carriage returns.
|
||||
*/
|
||||
|
||||
int socketGets(int sid, char_t **buf)
|
||||
{
|
||||
socket_t *sp;
|
||||
ringq_t *lq;
|
||||
char c;
|
||||
int rc, len;
|
||||
|
||||
a_assert(buf);
|
||||
*buf = NULL;
|
||||
|
||||
if ((sp = socketPtr(sid)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
lq = &sp->lineBuf;
|
||||
|
||||
while (1) {
|
||||
|
||||
if ((rc = socketRead(sid, &c, 1)) < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
/*
|
||||
* If there is a partial line and we are at EOF, pretend we saw a '\n'
|
||||
*/
|
||||
if (ringqLen(lq) > 0 && (sp->flags & SOCKET_EOF)) {
|
||||
c = '\n';
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If a newline is seen, return the data excluding the new line to the
|
||||
* caller. If carriage return is seen, just eat it.
|
||||
*/
|
||||
if (c == '\n') {
|
||||
len = ringqLen(lq);
|
||||
if (len > 0) {
|
||||
*buf = ballocAscToUni((char *)lq->servp, len);
|
||||
} else {
|
||||
*buf = NULL;
|
||||
}
|
||||
ringqFlush(lq);
|
||||
return len;
|
||||
|
||||
} else if (c == '\r') {
|
||||
continue;
|
||||
}
|
||||
ringqPutcA(lq, c);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Flush the socket. Block if the socket is in blocking mode.
|
||||
* This will return -1 on errors and 0 if successful.
|
||||
*/
|
||||
|
||||
int socketFlush(int sid)
|
||||
{
|
||||
socket_t *sp;
|
||||
ringq_t *rq;
|
||||
int len, bytesWritten, errCode;
|
||||
|
||||
if ((sp = socketPtr(sid)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
rq = &sp->outBuf;
|
||||
|
||||
/*
|
||||
* Set the background flushing flag which socketEventProc will check to
|
||||
* continue the flush.
|
||||
*/
|
||||
if (! (sp->flags & SOCKET_BLOCK)) {
|
||||
sp->flags |= SOCKET_FLUSHING;
|
||||
}
|
||||
|
||||
/*
|
||||
* Break from loop if not blocking after initiating output. If we are blocking
|
||||
* we wait for a write event.
|
||||
*/
|
||||
while (ringqLen(rq) > 0) {
|
||||
len = ringqGetBlkMax(&sp->outBuf);
|
||||
bytesWritten = socketDoOutput(sp, (char*) rq->servp, len, &errCode);
|
||||
if (bytesWritten < 0) {
|
||||
if (errCode == EINTR) {
|
||||
continue;
|
||||
} else if (errCode == EWOULDBLOCK || errCode == EAGAIN) {
|
||||
#if (defined (WIN) || defined (CE))
|
||||
if (sp->flags & SOCKET_BLOCK) {
|
||||
int errCode;
|
||||
if (! socketWaitForEvent(sp, FD_WRITE | SOCKET_WRITABLE,
|
||||
&errCode)) {
|
||||
return -1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Ensure we get a FD_WRITE message when the socket can absorb
|
||||
* more data (non-blocking only.) Store the user's mask if we
|
||||
* haven't done it already.
|
||||
*/
|
||||
if (sp->saveMask < 0 ) {
|
||||
sp->saveMask = sp->handlerMask;
|
||||
socketRegisterInterest(sp,
|
||||
sp->handlerMask | SOCKET_WRITABLE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
ringqGetBlkAdj(rq, bytesWritten);
|
||||
}
|
||||
/*
|
||||
* If the buffer is empty, reset the ringq pointers to point to the start
|
||||
* of the buffer. This is essential to ensure that datagrams get written
|
||||
* in one single I/O operation.
|
||||
*/
|
||||
if (ringqLen(rq) == 0) {
|
||||
ringqFlush(rq);
|
||||
}
|
||||
/*
|
||||
* Restore the users mask if it was saved by the non-blocking code above.
|
||||
* Note: saveMask = -1 if empty. socketRegisterInterest will set handlerMask
|
||||
*/
|
||||
if (sp->saveMask >= 0) {
|
||||
socketRegisterInterest(sp, sp->saveMask);
|
||||
sp->saveMask = -1;
|
||||
}
|
||||
sp->flags &= ~SOCKET_FLUSHING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Return the count of input characters buffered. We look at both the line
|
||||
* buffer and the input (raw) buffer. Return -1 on error or EOF.
|
||||
*/
|
||||
|
||||
int socketInputBuffered(int sid)
|
||||
{
|
||||
socket_t *sp;
|
||||
|
||||
if ((sp = socketPtr(sid)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (socketEof(sid)) {
|
||||
return -1;
|
||||
}
|
||||
return ringqLen(&sp->lineBuf) + ringqLen(&sp->inBuf);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Return true if EOF
|
||||
*/
|
||||
|
||||
int socketEof(int sid)
|
||||
{
|
||||
socket_t *sp;
|
||||
|
||||
if ((sp = socketPtr(sid)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return sp->flags & SOCKET_EOF;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Return the number of bytes the socket can absorb without blocking
|
||||
*/
|
||||
|
||||
int socketCanWrite(int sid)
|
||||
{
|
||||
socket_t *sp;
|
||||
|
||||
if ((sp = socketPtr(sid)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return sp->outBuf.buflen - ringqLen(&sp->outBuf) - 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Add one to allow the user to write exactly SOCKET_BUFSIZ
|
||||
*/
|
||||
|
||||
void socketSetBufferSize(int sid, int in, int line, int out)
|
||||
{
|
||||
socket_t *sp;
|
||||
|
||||
if ((sp = socketPtr(sid)) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (in >= 0) {
|
||||
ringqClose(&sp->inBuf);
|
||||
in++;
|
||||
ringqOpen(&sp->inBuf, in, in);
|
||||
}
|
||||
|
||||
if (line >= 0) {
|
||||
ringqClose(&sp->lineBuf);
|
||||
line++;
|
||||
ringqOpen(&sp->lineBuf, line, line);
|
||||
}
|
||||
|
||||
if (out >= 0) {
|
||||
ringqClose(&sp->outBuf);
|
||||
out++;
|
||||
ringqOpen(&sp->outBuf, out, out);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Create a user handler for this socket. The handler called whenever there
|
||||
* is an event of interest as defined by handlerMask (SOCKET_READABLE, ...)
|
||||
*/
|
||||
|
||||
void socketCreateHandler(int sid, int handlerMask, socketHandler_t handler,
|
||||
int data)
|
||||
{
|
||||
socket_t *sp;
|
||||
|
||||
if ((sp = socketPtr(sid)) == NULL) {
|
||||
return;
|
||||
}
|
||||
sp->handler = handler;
|
||||
sp->handler_data = data;
|
||||
socketRegisterInterest(sp, handlerMask);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Delete a handler
|
||||
*/
|
||||
|
||||
void socketDeleteHandler(int sid)
|
||||
{
|
||||
socket_t *sp;
|
||||
|
||||
if ((sp = socketPtr(sid)) == NULL) {
|
||||
return;
|
||||
}
|
||||
sp->handler = NULL;
|
||||
socketRegisterInterest(sp, 0);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Socket output procedure. Return -1 on errors otherwise return the number
|
||||
* of bytes written.
|
||||
*/
|
||||
|
||||
static int socketDoOutput(socket_t *sp, char *buf, int toWrite, int *errCode)
|
||||
{
|
||||
struct sockaddr_in server;
|
||||
int bytes;
|
||||
|
||||
a_assert(sp);
|
||||
a_assert(buf);
|
||||
a_assert(toWrite > 0);
|
||||
a_assert(errCode);
|
||||
|
||||
*errCode = 0;
|
||||
|
||||
#if (defined (WIN) || defined (CE))
|
||||
if ((sp->flags & SOCKET_ASYNC)
|
||||
&& ! socketWaitForEvent(sp, FD_CONNECT, errCode)) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Write the data
|
||||
*/
|
||||
if (sp->flags & SOCKET_BROADCAST) {
|
||||
server.sin_family = AF_INET;
|
||||
#if (defined (UEMF) || defined (LITTLEFOOT))
|
||||
server.sin_addr.s_addr = INADDR_BROADCAST;
|
||||
#else
|
||||
server.sin_addr.s_addr = inet_addr(basicGetBroadcastAddress());
|
||||
#endif
|
||||
server.sin_port = htons((short)(sp->port & 0xFFFF));
|
||||
if ((bytes = sendto(sp->sock, buf, toWrite, 0,
|
||||
(struct sockaddr *) &server, sizeof(server))) < 0) {
|
||||
bytes = tryAlternateSendTo(sp->sock, buf, toWrite, 0,
|
||||
(struct sockaddr *) &server);
|
||||
}
|
||||
} else if (sp->flags & SOCKET_DATAGRAM) {
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_addr.s_addr = inet_addr(sp->host);
|
||||
server.sin_port = htons((short)(sp->port & 0xFFFF));
|
||||
bytes = sendto(sp->sock, buf, toWrite, 0,
|
||||
(struct sockaddr *) &server, sizeof(server));
|
||||
|
||||
} else {
|
||||
bytes = send(sp->sock, buf, toWrite, 0);
|
||||
}
|
||||
|
||||
if (bytes < 0) {
|
||||
*errCode = socketGetError();
|
||||
#if (defined (WIN) || defined (CE))
|
||||
sp->currentEvents &= ~FD_WRITE;
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
|
||||
} else if (bytes == 0 && bytes != toWrite) {
|
||||
*errCode = EWOULDBLOCK;
|
||||
#if (defined (WIN) || defined (CE))
|
||||
sp->currentEvents &= ~FD_WRITE;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure we get to write some more data real soon if the socket can absorb
|
||||
* more data
|
||||
*/
|
||||
#ifndef UEMF
|
||||
#ifdef WIN
|
||||
if (sp->interestEvents & FD_WRITE) {
|
||||
emfTime_t blockTime = { 0, 0 };
|
||||
emfSetMaxBlockTime(&blockTime);
|
||||
}
|
||||
#endif /* WIN */
|
||||
#endif
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* If the sendto failed, swap the first two bytes in the
|
||||
* sockaddr structure. This is a kludge due to a change in
|
||||
* VxWorks between versions 5.3 and 5.4, but we want the
|
||||
* product to run on either.
|
||||
*/
|
||||
static int tryAlternateSendTo(int sock, char *buf, int toWrite, int i,
|
||||
struct sockaddr *server)
|
||||
{
|
||||
#ifdef VXWORKS
|
||||
char *ptr;
|
||||
|
||||
ptr = (char *)server;
|
||||
*ptr = *(ptr+1);
|
||||
*(ptr+1) = 0;
|
||||
return sendto(sock, buf, toWrite, i, server, sizeof(struct sockaddr));
|
||||
#else
|
||||
return -1;
|
||||
#endif /* VXWORKS */
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Allocate a new socket structure
|
||||
*/
|
||||
|
||||
int socketAlloc(char *host, int port, socketAccept_t accept, int flags)
|
||||
{
|
||||
socket_t *sp;
|
||||
int sid;
|
||||
|
||||
if ((sid = hAllocEntry((void*) &socketList, &socketMax,
|
||||
sizeof(socket_t))) < 0) {
|
||||
return -1;
|
||||
}
|
||||
sp = socketList[sid];
|
||||
|
||||
sp->sid = sid;
|
||||
sp->accept = accept;
|
||||
sp->port = port;
|
||||
sp->fileHandle = -1;
|
||||
sp->saveMask = -1;
|
||||
|
||||
if (host) {
|
||||
strncpy(sp->host, host, sizeof(sp->host));
|
||||
}
|
||||
|
||||
/*
|
||||
* Preserve only specified flags from the callers open
|
||||
*/
|
||||
a_assert((flags & ~(SOCKET_BROADCAST|SOCKET_DATAGRAM|SOCKET_BLOCK|
|
||||
SOCKET_LISTENING)) == 0);
|
||||
sp->flags = flags & (SOCKET_BROADCAST | SOCKET_DATAGRAM | SOCKET_BLOCK|
|
||||
SOCKET_LISTENING);
|
||||
|
||||
/*
|
||||
* Add one to allow the user to write exactly SOCKET_BUFSIZ
|
||||
*/
|
||||
ringqOpen(&sp->inBuf, SOCKET_BUFSIZ, SOCKET_BUFSIZ);
|
||||
ringqOpen(&sp->outBuf, SOCKET_BUFSIZ + 1, SOCKET_BUFSIZ + 1);
|
||||
ringqOpen(&sp->lineBuf, SOCKET_BUFSIZ, -1);
|
||||
|
||||
return sid;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Free a socket structure
|
||||
*/
|
||||
|
||||
void socketFree(int sid)
|
||||
{
|
||||
socket_t *sp;
|
||||
char_t buf[256];
|
||||
int i;
|
||||
|
||||
if ((sp = socketPtr(sid)) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* To close a socket, remove any registered interests, set it to
|
||||
* non-blocking so that the recv which follows won't block, do a
|
||||
* shutdown on it so peers on the other end will receive a FIN,
|
||||
* then read any data not yet retrieved from the receive buffer,
|
||||
* and finally close it. If these steps are not all performed
|
||||
* RESETs may be sent to the other end causing problems.
|
||||
*/
|
||||
socketRegisterInterest(sp, 0);
|
||||
if (sp->sock >= 0) {
|
||||
socketSetBlock(sid, 0);
|
||||
if (shutdown(sp->sock, 1) >= 0) {
|
||||
recv(sp->sock, buf, sizeof(buf), 0);
|
||||
}
|
||||
#if (defined (WIN) || defined (CE))
|
||||
closesocket(sp->sock);
|
||||
#else
|
||||
close(sp->sock);
|
||||
#endif
|
||||
}
|
||||
|
||||
ringqClose(&sp->inBuf);
|
||||
ringqClose(&sp->outBuf);
|
||||
ringqClose(&sp->lineBuf);
|
||||
|
||||
bfree(B_L, sp);
|
||||
socketMax = hFree((void*) &socketList, sid);
|
||||
|
||||
/*
|
||||
* Calculate the new highest socket number
|
||||
*/
|
||||
socketHighestFd = -1;
|
||||
for (i = 0; i < socketMax; i++) {
|
||||
if ((sp = socketList[i]) == NULL) {
|
||||
continue;
|
||||
}
|
||||
socketHighestFd = max(socketHighestFd, sp->sock);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Validate a socket handle
|
||||
*/
|
||||
|
||||
socket_t *socketPtr(int sid)
|
||||
{
|
||||
if (sid < 0 || sid >= socketMax || socketList[sid] == NULL) {
|
||||
a_assert(NULL);
|
||||
errno = EBADF;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
a_assert(socketList[sid]);
|
||||
return socketList[sid];
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Get the operating system error code
|
||||
*/
|
||||
|
||||
int socketGetError()
|
||||
{
|
||||
#if (defined (WIN) || defined (CE))
|
||||
switch (WSAGetLastError()) {
|
||||
case WSAEWOULDBLOCK:
|
||||
return EWOULDBLOCK;
|
||||
case WSAECONNRESET:
|
||||
return ECONNRESET;
|
||||
case WSAENETDOWN:
|
||||
return ENETDOWN;
|
||||
case WSAEPROCLIM:
|
||||
return EAGAIN;
|
||||
case WSAEINTR:
|
||||
return EINTR;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
#else
|
||||
return errno;
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Return the underlying socket handle
|
||||
*/
|
||||
|
||||
int socketGetHandle(int sid)
|
||||
{
|
||||
socket_t *sp;
|
||||
|
||||
if ((sp = socketPtr(sid)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return sp->sock;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Get blocking mode
|
||||
*/
|
||||
|
||||
int socketGetBlock(int sid)
|
||||
{
|
||||
socket_t *sp;
|
||||
|
||||
if ((sp = socketPtr(sid)) == NULL) {
|
||||
a_assert(0);
|
||||
return 0;
|
||||
}
|
||||
return (sp->flags & SOCKET_BLOCK);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Get mode
|
||||
*/
|
||||
|
||||
int socketGetMode(int sid)
|
||||
{
|
||||
socket_t *sp;
|
||||
|
||||
if ((sp = socketPtr(sid)) == NULL) {
|
||||
a_assert(0);
|
||||
return 0;
|
||||
}
|
||||
return sp->flags;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Set mode
|
||||
*/
|
||||
|
||||
void socketSetMode(int sid, int mode)
|
||||
{
|
||||
socket_t *sp;
|
||||
|
||||
if ((sp = socketPtr(sid)) == NULL) {
|
||||
a_assert(0);
|
||||
return;
|
||||
}
|
||||
sp->flags = mode;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Get port.
|
||||
*/
|
||||
|
||||
int socketGetPort(int sid)
|
||||
{
|
||||
socket_t *sp;
|
||||
|
||||
if ((sp = socketPtr(sid)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return sp->port;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,474 +0,0 @@
|
||||
/*
|
||||
* sym.c -- Symbol Table module
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
/*
|
||||
* This module implements a highly efficient generic symbol table with
|
||||
* update and access routines. Symbols are simple character strings and
|
||||
* the values they take can be flexible types as defined by value_t.
|
||||
* This modules allows multiple symbol tables to be created.
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#ifdef UEMF
|
||||
#include "uemf.h"
|
||||
#else
|
||||
#include "basic/basicInternal.h"
|
||||
#endif
|
||||
|
||||
/********************************* Defines ************************************/
|
||||
|
||||
typedef struct { /* Symbol table descriptor */
|
||||
int inuse; /* Is this entry in use */
|
||||
int hash_size; /* Size of the table below */
|
||||
sym_t **hash_table; /* Allocated at run time */
|
||||
} sym_tabent_t;
|
||||
|
||||
/********************************* Globals ************************************/
|
||||
|
||||
static sym_tabent_t **sym; /* List of symbol tables */
|
||||
static int symMax; /* One past the max symbol table */
|
||||
static int symOpenCount = 0; /* Count of apps using sym */
|
||||
|
||||
static int htIndex; /* Current location in table */
|
||||
static sym_t* next; /* Next symbol in iteration */
|
||||
|
||||
/**************************** Forward Declarations ****************************/
|
||||
|
||||
static int hashIndex(sym_tabent_t *tp, char_t *name);
|
||||
static sym_t *hash(sym_tabent_t *tp, char_t *name);
|
||||
static int calcPrime(int size);
|
||||
|
||||
/*********************************** Code *************************************/
|
||||
/*
|
||||
* Open the symbol table subSystem.
|
||||
*/
|
||||
|
||||
int symSubOpen()
|
||||
{
|
||||
if (++symOpenCount == 1) {
|
||||
symMax = 0;
|
||||
sym = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Close the symbol table subSystem.
|
||||
*/
|
||||
|
||||
void symSubClose()
|
||||
{
|
||||
if (--symOpenCount <= 0) {
|
||||
symOpenCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Create a symbol table.
|
||||
*/
|
||||
|
||||
sym_fd_t symOpen(int hash_size)
|
||||
{
|
||||
sym_fd_t sd;
|
||||
sym_tabent_t *tp;
|
||||
|
||||
a_assert(hash_size > 2);
|
||||
|
||||
/*
|
||||
* Create a new handle for this symbol table
|
||||
*/
|
||||
if ((sd = hAlloc((void*) &sym)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new symbol table structure and zero
|
||||
*/
|
||||
if ((tp = (sym_tabent_t*) balloc(B_L, sizeof(sym_tabent_t))) == NULL) {
|
||||
symMax = hFree((void*) &sym, sd);
|
||||
return -1;
|
||||
}
|
||||
memset(tp, 0, sizeof(sym_tabent_t));
|
||||
if (sd >= symMax) {
|
||||
symMax = sd + 1;
|
||||
}
|
||||
a_assert(0 <= sd && sd < symMax);
|
||||
sym[sd] = tp;
|
||||
|
||||
/*
|
||||
* Now create the hash table for fast indexing.
|
||||
*/
|
||||
tp->hash_size = calcPrime(hash_size);
|
||||
tp->hash_table = (sym_t**) balloc(B_L, tp->hash_size * sizeof(sym_t*));
|
||||
a_assert(tp->hash_table);
|
||||
memset(tp->hash_table, 0, tp->hash_size * sizeof(sym_t*));
|
||||
|
||||
return sd;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Close this symbol table. Call a cleanup function to allow the caller
|
||||
* to free resources associated with each symbol table entry.
|
||||
*/
|
||||
|
||||
void symClose(sym_fd_t sd)
|
||||
{
|
||||
sym_tabent_t *tp;
|
||||
sym_t *sp, *forw;
|
||||
int i;
|
||||
|
||||
a_assert(0 <= sd && sd < symMax);
|
||||
tp = sym[sd];
|
||||
a_assert(tp);
|
||||
|
||||
/*
|
||||
* Free all symbols in the hash table, then the hash table itself.
|
||||
*/
|
||||
for (i = 0; i < tp->hash_size; i++) {
|
||||
for (sp = tp->hash_table[i]; sp; sp = forw) {
|
||||
forw = sp->forw;
|
||||
valueFree(&sp->name);
|
||||
valueFree(&sp->content);
|
||||
bfree(B_L, (void*) sp);
|
||||
sp = forw;
|
||||
}
|
||||
}
|
||||
bfree(B_L, (void*) tp->hash_table);
|
||||
|
||||
symMax = hFree((void*) &sym, sd);
|
||||
bfree(B_L, (void*) tp);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Return the first symbol in the hashtable if there is one. This call is used
|
||||
* as the first step in traversing the table. A call to symFirst should be
|
||||
* followed by calls to symNext to get all the rest of the entries.
|
||||
*/
|
||||
|
||||
sym_t* symFirst(sym_fd_t sd)
|
||||
{
|
||||
sym_tabent_t *tp;
|
||||
sym_t *sp, *forw;
|
||||
int i;
|
||||
|
||||
a_assert(0 <= sd && sd < symMax);
|
||||
tp = sym[sd];
|
||||
a_assert(tp);
|
||||
|
||||
/*
|
||||
* Find the first symbol in the hashtable and return a pointer to it.
|
||||
*/
|
||||
for (i = 0; i < tp->hash_size; i++) {
|
||||
for (sp = tp->hash_table[i]; sp; sp = forw) {
|
||||
forw = sp->forw;
|
||||
|
||||
if (forw == NULL) {
|
||||
htIndex = i + 1;
|
||||
next = tp->hash_table[htIndex];
|
||||
} else {
|
||||
htIndex = i;
|
||||
next = forw;
|
||||
}
|
||||
return sp;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Return the next symbol in the hashtable if there is one. See symFirst.
|
||||
*/
|
||||
|
||||
sym_t* symNext(sym_fd_t sd)
|
||||
{
|
||||
sym_tabent_t *tp;
|
||||
sym_t *sp, *forw;
|
||||
int i;
|
||||
|
||||
a_assert(0 <= sd && sd < symMax);
|
||||
tp = sym[sd];
|
||||
a_assert(tp);
|
||||
|
||||
/*
|
||||
* Find the first symbol in the hashtable and return a pointer to it.
|
||||
*/
|
||||
for (i = htIndex; i < tp->hash_size; i++) {
|
||||
for (sp = next; sp; sp = forw) {
|
||||
forw = sp->forw;
|
||||
|
||||
if (forw == NULL) {
|
||||
htIndex = i + 1;
|
||||
next = tp->hash_table[htIndex];
|
||||
} else {
|
||||
htIndex = i;
|
||||
next = forw;
|
||||
}
|
||||
return sp;
|
||||
}
|
||||
next = tp->hash_table[i + 1];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Lookup a symbol and return a pointer to the symbol entry. If not present
|
||||
* then return a NULL.
|
||||
*/
|
||||
|
||||
sym_t *symLookup(sym_fd_t sd, char_t *name)
|
||||
{
|
||||
sym_tabent_t *tp;
|
||||
sym_t *sp;
|
||||
char_t *cp;
|
||||
|
||||
a_assert(0 <= sd && sd < symMax);
|
||||
if ((tp = sym[sd]) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (name == NULL || *name == '\0') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do an initial hash and then follow the link chain to find the right entry
|
||||
*/
|
||||
for (sp = hash(tp, name); sp; sp = sp->forw) {
|
||||
cp = sp->name.value.string;
|
||||
if (cp[0] == name[0] && gstrcmp(cp, name) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sp;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Enter a symbol into the table. If already there, update its value.
|
||||
* Always succeeds if memory available. We allocate a copy of "name" here
|
||||
* so it can be a volatile variable. The value "v" is just a copy of the
|
||||
* passed in value, so it MUST be persistent.
|
||||
*/
|
||||
|
||||
sym_t *symEnter(sym_fd_t sd, char_t *name, value_t v, int arg)
|
||||
{
|
||||
sym_tabent_t *tp;
|
||||
sym_t *sp, *last;
|
||||
char_t *cp;
|
||||
int hindex;
|
||||
|
||||
a_assert(name);
|
||||
a_assert(0 <= sd && sd < symMax);
|
||||
tp = sym[sd];
|
||||
a_assert(tp);
|
||||
|
||||
/*
|
||||
* Calculate the first daisy-chain from the hash table. If non-zero, then
|
||||
* we have daisy-chain, so scan it and look for the symbol.
|
||||
*/
|
||||
last = NULL;
|
||||
hindex = hashIndex(tp, name);
|
||||
if ((sp = tp->hash_table[hindex]) != NULL) {
|
||||
for (; sp; sp = sp->forw) {
|
||||
cp = sp->name.value.string;
|
||||
if (cp[0] == name[0] && gstrcmp(cp, name) == 0) {
|
||||
break;
|
||||
}
|
||||
last = sp;
|
||||
}
|
||||
if (sp) {
|
||||
/*
|
||||
* Found, so update the value
|
||||
* If the caller stores handles which require freeing, they
|
||||
* will be lost here. It is the callers responsibility to free
|
||||
* resources before overwriting existing contents. We will here
|
||||
* free allocated strings which occur due to value_instring().
|
||||
* We should consider providing the cleanup function on the open rather
|
||||
* than the close and then we could call it here and solve the problem.
|
||||
*/
|
||||
if (sp->content.valid) {
|
||||
valueFree(&sp->content);
|
||||
}
|
||||
sp->content = v;
|
||||
sp->arg = arg;
|
||||
return sp;
|
||||
}
|
||||
/*
|
||||
* Not found so allocate and append to the daisy-chain
|
||||
*/
|
||||
sp = (sym_t*) balloc(B_L, sizeof(sym_t));
|
||||
if (sp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
sp->name = valueString(name, VALUE_ALLOCATE);
|
||||
sp->content = v;
|
||||
sp->forw = (sym_t*) NULL;
|
||||
sp->arg = arg;
|
||||
last->forw = sp;
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Daisy chain is empty so we need to start the chain
|
||||
*/
|
||||
sp = (sym_t*) balloc(B_L, sizeof(sym_t));
|
||||
if (sp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
tp->hash_table[hindex] = sp;
|
||||
tp->hash_table[hashIndex(tp, name)] = sp;
|
||||
|
||||
sp->forw = (sym_t*) NULL;
|
||||
sp->content = v;
|
||||
sp->arg = arg;
|
||||
sp->name = valueString(name, VALUE_ALLOCATE);
|
||||
}
|
||||
return sp;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Delete a symbol from a table
|
||||
*/
|
||||
|
||||
int symDelete(sym_fd_t sd, char_t *name)
|
||||
{
|
||||
sym_tabent_t *tp;
|
||||
sym_t *sp, *last;
|
||||
char_t *cp;
|
||||
int hindex;
|
||||
|
||||
a_assert(name && *name);
|
||||
a_assert(0 <= sd && sd < symMax);
|
||||
tp = sym[sd];
|
||||
a_assert(tp);
|
||||
|
||||
/*
|
||||
* Calculate the first daisy-chain from the hash table. If non-zero, then
|
||||
* we have daisy-chain, so scan it and look for the symbol.
|
||||
*/
|
||||
last = NULL;
|
||||
hindex = hashIndex(tp, name);
|
||||
if ((sp = tp->hash_table[hindex]) != NULL) {
|
||||
for ( ; sp; sp = sp->forw) {
|
||||
cp = sp->name.value.string;
|
||||
if (cp[0] == name[0] && gstrcmp(cp, name) == 0) {
|
||||
break;
|
||||
}
|
||||
last = sp;
|
||||
}
|
||||
}
|
||||
if (sp == (sym_t*) NULL) { /* Not Found */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlink and free the symbol. Last will be set if the element to be deleted
|
||||
* is not first in the chain.
|
||||
*/
|
||||
if (last) {
|
||||
last->forw = sp->forw;
|
||||
} else {
|
||||
tp->hash_table[hindex] = sp->forw;
|
||||
}
|
||||
valueFree(&sp->name);
|
||||
valueFree(&sp->content);
|
||||
bfree(B_L, (void*) sp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Hash a symbol and return a pointer to the hash daisy-chain list
|
||||
* All symbols reside on the chain (ie. none stored in the hash table itself)
|
||||
*/
|
||||
|
||||
static sym_t *hash(sym_tabent_t *tp, char_t *name)
|
||||
{
|
||||
a_assert(tp);
|
||||
|
||||
return tp->hash_table[hashIndex(tp, name)];
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Compute the hash function and return an index into the hash table
|
||||
* We use a basic additive function that is then made modulo the size of the
|
||||
* table.
|
||||
*/
|
||||
|
||||
static int hashIndex(sym_tabent_t *tp, char_t *name)
|
||||
{
|
||||
unsigned int sum;
|
||||
int i;
|
||||
|
||||
a_assert(tp);
|
||||
/*
|
||||
* Add in each character shifted up progressively by 7 bits. The shift
|
||||
* amount is rounded so as to not shift too far. It thus cycles with each
|
||||
* new cycle placing character shifted up by one bit.
|
||||
*/
|
||||
i = 0;
|
||||
sum = 0;
|
||||
while (*name) {
|
||||
sum += (((int) *name++) << i);
|
||||
i = (i + 7) % (BITS(int) - BITSPERBYTE);
|
||||
}
|
||||
return sum % tp->hash_size;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Check if this number is a prime
|
||||
*/
|
||||
|
||||
static int isPrime(int n)
|
||||
{
|
||||
int i, max;
|
||||
|
||||
a_assert(n > 0);
|
||||
|
||||
max = n / 2;
|
||||
for (i = 2; i <= max; i++) {
|
||||
if (n % i == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Calculate the largest prime smaller than size.
|
||||
*/
|
||||
|
||||
static int calcPrime(int size)
|
||||
{
|
||||
int count;
|
||||
|
||||
a_assert(size > 0);
|
||||
|
||||
for (count = size; count > 0; count--) {
|
||||
if (isPrime(count)) {
|
||||
return count;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,293 +0,0 @@
|
||||
/*
|
||||
* uemf.c -- GoAhead Micro Embedded Management Framework
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/********************************** Description *******************************/
|
||||
|
||||
/*
|
||||
* This module provides compatibility with the full GoAhead EMF.
|
||||
* It is a collection of routines which permits the GoAhead WebServer to
|
||||
* run stand-alone and to also load as a solution pack under the GoAhead EMF.
|
||||
*/
|
||||
|
||||
/*********************************** Includes *********************************/
|
||||
|
||||
#include "uemf.h"
|
||||
|
||||
/********************************** Local Data ********************************/
|
||||
|
||||
int emfInst; /* Application instance handle */
|
||||
|
||||
/****************************** Forward Declarations **************************/
|
||||
|
||||
extern void defaultErrorHandler(int etype, char_t *buf);
|
||||
static void (*errorHandler)(int etype, char_t *msg) = defaultErrorHandler;
|
||||
|
||||
extern void defaultTraceHandler(int level, char_t *buf);
|
||||
static void (*traceHandler)(int level, char_t *buf) = defaultTraceHandler;
|
||||
|
||||
/************************************* Code ***********************************/
|
||||
/*
|
||||
* Error message that doesn't need user attention. Customize this code
|
||||
* to direct error messages to wherever the developer wishes
|
||||
*/
|
||||
|
||||
void error(E_ARGS_DEC, int etype, char_t *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char_t *fmtBuf, *buf;
|
||||
|
||||
va_start(args, fmt);
|
||||
fmtValloc(&fmtBuf, E_MAX_ERROR, fmt, args);
|
||||
|
||||
if (etype == E_LOG) {
|
||||
fmtAlloc(&buf, E_MAX_ERROR, T("%s\n"), fmtBuf);
|
||||
/*#ifdef DEV*/
|
||||
} else if (etype == E_ASSERT) {
|
||||
fmtAlloc(&buf, E_MAX_ERROR,
|
||||
T("Assertion %s, failed at %s %d\n"), fmtBuf, E_ARGS);
|
||||
/*#endif*/
|
||||
} else if (etype == E_USER) {
|
||||
fmtAlloc(&buf, E_MAX_ERROR, T("%s\n"), fmtBuf);
|
||||
}
|
||||
/*
|
||||
* bugfix -- if etype is not E_LOG, E_ASSERT, or E_USER, the call to
|
||||
* bfreeSafe(B_L, buf) below will fail, because 'buf' is randomly
|
||||
* initialized. To be nice, we format a message saying that this is an
|
||||
* unknown message type, and in doing so give buf a valid value. Thanks
|
||||
* to Simon Byholm.
|
||||
*/
|
||||
else {
|
||||
fmtAlloc(&buf, E_MAX_ERROR, T("Unknown error"));
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
bfree(B_L, fmtBuf);
|
||||
|
||||
if (errorHandler) {
|
||||
errorHandler(etype, buf);
|
||||
}
|
||||
|
||||
bfreeSafe(B_L, buf);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Replace the default error handler. Return pointer to old error handler.
|
||||
*/
|
||||
|
||||
void (*errorSetHandler(void (*function)(int etype, char_t *msg))) \
|
||||
(int etype, char_t *msg)
|
||||
{
|
||||
void (*oldHandler)(int etype, char_t *buf);
|
||||
|
||||
oldHandler = errorHandler;
|
||||
errorHandler = function;
|
||||
return oldHandler;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Trace log. Customize this function to log trace output
|
||||
*/
|
||||
|
||||
void trace(int level, char_t *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char_t *buf;
|
||||
|
||||
va_start(args, fmt);
|
||||
fmtValloc(&buf, VALUE_MAX_STRING, fmt, args);
|
||||
|
||||
if (traceHandler) {
|
||||
traceHandler(level, buf);
|
||||
}
|
||||
bfreeSafe(B_L, buf);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Trace log. Customize this function to log trace output
|
||||
*/
|
||||
|
||||
void traceRaw(char_t *buf)
|
||||
{
|
||||
if (traceHandler) {
|
||||
traceHandler(0, buf);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Replace the default trace handler. Return a pointer to the old handler.
|
||||
*/
|
||||
|
||||
void (*traceSetHandler(void (*function)(int level, char_t *buf)))
|
||||
(int level, char *buf)
|
||||
{
|
||||
void (*oldHandler)(int level, char_t *buf);
|
||||
|
||||
oldHandler = traceHandler;
|
||||
if (function) {
|
||||
traceHandler = function;
|
||||
}
|
||||
return oldHandler;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Save the instance handle
|
||||
*/
|
||||
|
||||
void emfInstSet(int inst)
|
||||
{
|
||||
emfInst = inst;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Get the instance handle
|
||||
*/
|
||||
|
||||
int emfInstGet()
|
||||
{
|
||||
return emfInst;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Convert a string to lower case
|
||||
*/
|
||||
|
||||
char_t *strlower(char_t *string)
|
||||
{
|
||||
char_t *s;
|
||||
|
||||
a_assert(string);
|
||||
|
||||
if (string == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = string;
|
||||
while (*s) {
|
||||
if (gisupper(*s)) {
|
||||
*s = (char_t) gtolower(*s);
|
||||
}
|
||||
s++;
|
||||
}
|
||||
*s = '\0';
|
||||
return string;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Convert a string to upper case
|
||||
*/
|
||||
|
||||
char_t *strupper(char_t *string)
|
||||
{
|
||||
char_t *s;
|
||||
|
||||
a_assert(string);
|
||||
if (string == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = string;
|
||||
while (*s) {
|
||||
if (gislower(*s)) {
|
||||
*s = (char_t) gtoupper(*s);
|
||||
}
|
||||
s++;
|
||||
}
|
||||
*s = '\0';
|
||||
return string;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Convert integer to ascii string. Allow a NULL string in which case we
|
||||
* allocate a dynamic buffer.
|
||||
*/
|
||||
|
||||
char_t *stritoa(int n, char_t *string, int width)
|
||||
{
|
||||
char_t *cp, *lim, *s;
|
||||
char_t buf[16]; /* Just temp to hold number */
|
||||
int next, minus;
|
||||
|
||||
a_assert(string && width > 0);
|
||||
|
||||
if (string == NULL) {
|
||||
if (width == 0) {
|
||||
width = 10;
|
||||
}
|
||||
if ((string = balloc(B_L, width + 1)) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (n < 0) {
|
||||
minus = 1;
|
||||
n = -n;
|
||||
width--;
|
||||
} else {
|
||||
minus = 0;
|
||||
}
|
||||
|
||||
cp = buf;
|
||||
lim = &buf[width - 1];
|
||||
while (n > 9 && cp < lim) {
|
||||
next = n;
|
||||
n /= 10;
|
||||
*cp++ = (char_t) (next - n * 10 + '0');
|
||||
}
|
||||
if (cp < lim) {
|
||||
*cp++ = (char_t) (n + '0');
|
||||
}
|
||||
|
||||
s = string;
|
||||
if (minus) {
|
||||
*s++ = '-';
|
||||
}
|
||||
|
||||
while (cp > buf) {
|
||||
*s++ = *--cp;
|
||||
}
|
||||
|
||||
*s++ = '\0';
|
||||
return string;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Stubs
|
||||
*/
|
||||
|
||||
char_t *basicGetProduct()
|
||||
{
|
||||
return T("uemf");
|
||||
}
|
||||
|
||||
char_t *basicGetAddress()
|
||||
{
|
||||
return T("localhost");
|
||||
}
|
||||
|
||||
int errorOpen(char_t *pname)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void errorClose()
|
||||
{
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,183 +0,0 @@
|
||||
/*
|
||||
* um.h -- GoAhead User Management public header
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1992-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for information on usage and redistribution
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _h_UM
|
||||
#define _h_UM 1
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* GoAhead User Management header. This defines the User Management
|
||||
* public APIs. Include this header for files that contain access to
|
||||
* user inquiry or management.
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#ifndef UEMF
|
||||
#include "basic/basic.h"
|
||||
#include "emf/emf.h"
|
||||
#else
|
||||
#include "uemf.h"
|
||||
#endif
|
||||
|
||||
/********************************** Defines ***********************************/
|
||||
|
||||
/*
|
||||
* Error Return Flags
|
||||
*/
|
||||
#define UM_OK 0
|
||||
#define UM_ERR_GENERAL -1
|
||||
#define UM_ERR_NOT_FOUND -2
|
||||
#define UM_ERR_PROTECTED -3
|
||||
#define UM_ERR_DUPLICATE -4
|
||||
#define UM_ERR_IN_USE -5
|
||||
#define UM_ERR_BAD_NAME -6
|
||||
#define UM_ERR_BAD_PASSWORD -7
|
||||
|
||||
/*
|
||||
* Privilege Masks
|
||||
*/
|
||||
#define PRIV_NONE 0x00
|
||||
#define PRIV_READ 0x01
|
||||
#define PRIV_WRITE 0x02
|
||||
#define PRIV_ADMIN 0x04
|
||||
|
||||
/*
|
||||
* User classes
|
||||
*/
|
||||
typedef short bool_t;
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
AM_NONE = 0,
|
||||
AM_FULL,
|
||||
AM_BASIC,
|
||||
AM_DIGEST,
|
||||
AM_INVALID
|
||||
} accessMeth_t;
|
||||
|
||||
/********************************** Prototypes ********************************/
|
||||
|
||||
/*
|
||||
* umOpen() must be called before accessing User Management functions
|
||||
*/
|
||||
extern int umOpen();
|
||||
|
||||
/*
|
||||
* umClose() should be called before shutdown to free memory
|
||||
*/
|
||||
extern void umClose();
|
||||
|
||||
/*
|
||||
* umCommit() persists the user management database
|
||||
*/
|
||||
extern int umCommit(char_t *filename);
|
||||
|
||||
/*
|
||||
* umRestore() loads the user management database
|
||||
*/
|
||||
extern int umRestore(char_t *filename);
|
||||
|
||||
/*
|
||||
* umUser functions use a user ID for a key
|
||||
*/
|
||||
extern int umAddUser(char_t *user, char_t *password,
|
||||
char_t *group, bool_t protect, bool_t disabled);
|
||||
|
||||
extern int umDeleteUser(char_t *user);
|
||||
|
||||
extern char_t *umGetFirstUser();
|
||||
extern char_t *umGetNextUser(char_t *lastUser);
|
||||
|
||||
extern bool_t umUserExists(char_t *user);
|
||||
|
||||
extern char_t *umGetUserPassword(char_t *user);
|
||||
extern int umSetUserPassword(char_t *user, char_t *password);
|
||||
|
||||
extern char_t *umGetUserGroup(char_t *user);
|
||||
extern int umSetUserGroup(char_t *user, char_t *password);
|
||||
|
||||
extern bool_t umGetUserEnabled(char_t *user);
|
||||
extern int umSetUserEnabled(char_t *user, bool_t enabled);
|
||||
|
||||
extern bool_t umGetUserProtected(char_t *user);
|
||||
extern int umSetUserProtected(char_t *user, bool_t protect);
|
||||
|
||||
/*
|
||||
* umGroup functions use a group name for a key
|
||||
*/
|
||||
extern int umAddGroup(char_t *group, short privilege,
|
||||
accessMeth_t am, bool_t protect, bool_t disabled);
|
||||
|
||||
extern int umDeleteGroup(char_t *group);
|
||||
|
||||
extern char_t *umGetFirstGroup();
|
||||
extern char_t *umGetNextGroup(char_t *lastUser);
|
||||
|
||||
extern bool_t umGroupExists(char_t *group);
|
||||
extern bool_t umGetGroupInUse(char_t *group);
|
||||
|
||||
extern accessMeth_t umGetGroupAccessMethod(char_t *group);
|
||||
extern int umSetGroupAccessMethod(char_t *group, accessMeth_t am);
|
||||
|
||||
extern bool_t umGetGroupEnabled(char_t *group);
|
||||
extern int umSetGroupEnabled(char_t *group, bool_t enabled);
|
||||
|
||||
extern short umGetGroupPrivilege(char_t *group);
|
||||
extern int umSetGroupPrivilege(char_t *group, short privileges);
|
||||
|
||||
extern bool_t umGetGroupProtected(char_t *group);
|
||||
extern int umSetGroupProtected(char_t *group, bool_t protect);
|
||||
|
||||
/*
|
||||
* umAccessLimit functions use a URL as a key
|
||||
*/
|
||||
extern int umAddAccessLimit(char_t *url, accessMeth_t am,
|
||||
short secure, char_t *group);
|
||||
|
||||
extern int umDeleteAccessLimit(char_t *url);
|
||||
|
||||
extern char_t *umGetFirstAccessLimit();
|
||||
extern char_t *umGetNextAccessLimit(char_t *lastUser);
|
||||
|
||||
/*
|
||||
* Returns the name of an ancestor access limit if
|
||||
*/
|
||||
extern char_t *umGetAccessLimit(char_t *url);
|
||||
|
||||
extern bool_t umAccessLimitExists(char_t *url);
|
||||
|
||||
extern accessMeth_t umGetAccessLimitMethod(char_t *url);
|
||||
extern int umSetAccessLimitMethod(char_t *url, accessMeth_t am);
|
||||
|
||||
extern short umGetAccessLimitSecure(char_t *url);
|
||||
extern int umSetAccessLimitSecure(char_t *url, short secure);
|
||||
|
||||
extern char_t *umGetAccessLimitGroup(char_t *url);
|
||||
extern int umSetAccessLimitGroup(char_t *url, char_t *group);
|
||||
|
||||
/*
|
||||
* Convenience Functions
|
||||
*/
|
||||
|
||||
extern accessMeth_t umGetAccessMethodForURL(char_t *url);
|
||||
extern bool_t umUserCanAccessURL(char_t *user, char_t *url);
|
||||
|
||||
#endif /* _h_UM */
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,641 +0,0 @@
|
||||
/*
|
||||
* umui.c -- User Management GoForm Processing
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* This module provides GoForm functions for User management
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#include "wsIntrn.h"
|
||||
#include "um.h"
|
||||
|
||||
/********************************* Defines ************************************/
|
||||
|
||||
#define NONE_OPTION T("<NONE>")
|
||||
#define MSG_START T("<body><h2>")
|
||||
#define MSG_END T("</h2></body>")
|
||||
|
||||
/**************************** Forward Declarations ****************************/
|
||||
|
||||
static void formAddUser(webs_t wp, char_t *path, char_t *query);
|
||||
static void formDeleteUser(webs_t wp, char_t *path, char_t *query);
|
||||
static void formDisplayUser(webs_t wp, char_t *path, char_t *query);
|
||||
static int aspGenerateUserList(int eid, webs_t wp,
|
||||
int argc, char_t **argv);
|
||||
|
||||
static void formAddGroup(webs_t wp, char_t *path, char_t *query);
|
||||
static void formDeleteGroup(webs_t wp, char_t *path, char_t *query);
|
||||
static int aspGenerateGroupList(int eid, webs_t wp,
|
||||
int argc, char_t **argv);
|
||||
|
||||
static void formAddAccessLimit(webs_t wp, char_t *path, char_t *query);
|
||||
static void formDeleteAccessLimit(webs_t wp, char_t *path, char_t *query);
|
||||
static int aspGenerateAccessLimitList(int eid, webs_t wp,
|
||||
int argc, char_t **argv);
|
||||
|
||||
static int aspGenerateAccessMethodList(int eid, webs_t wp,
|
||||
int argc, char_t **argv);
|
||||
static int aspGeneratePrivilegeList(int eid, webs_t wp,
|
||||
int argc, char_t **argv);
|
||||
|
||||
static void formSaveUserManagement(webs_t wp, char_t *path, char_t *query);
|
||||
static void formLoadUserManagement(webs_t wp, char_t *path, char_t *query);
|
||||
|
||||
static void websMsgStart(webs_t wp);
|
||||
static void websMsgEnd(webs_t wp);
|
||||
|
||||
/*********************************** Code *************************************/
|
||||
/*
|
||||
* Set up the User Management form handlers
|
||||
*/
|
||||
|
||||
void formDefineUserMgmt(void)
|
||||
{
|
||||
websAspDefine(T("MakeGroupList"), aspGenerateGroupList);
|
||||
websAspDefine(T("MakeUserList"), aspGenerateUserList);
|
||||
websAspDefine(T("MakeAccessLimitList"), aspGenerateAccessLimitList);
|
||||
websAspDefine(T("MakeAccessMethodList"), aspGenerateAccessMethodList);
|
||||
websAspDefine(T("MakePrivilegeList"), aspGeneratePrivilegeList);
|
||||
|
||||
websFormDefine(T("AddUser"), formAddUser);
|
||||
websFormDefine(T("DeleteUser"), formDeleteUser);
|
||||
websFormDefine(T("DisplayUser"), formDisplayUser);
|
||||
websFormDefine(T("AddGroup"), formAddGroup);
|
||||
websFormDefine(T("DeleteGroup"), formDeleteGroup);
|
||||
websFormDefine(T("AddAccessLimit"), formAddAccessLimit);
|
||||
websFormDefine(T("DeleteAccessLimit"), formDeleteAccessLimit);
|
||||
|
||||
websFormDefine(T("SaveUserManagement"), formSaveUserManagement);
|
||||
websFormDefine(T("LoadUserManagement"), formLoadUserManagement);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Add a user
|
||||
*/
|
||||
|
||||
static void formAddUser(webs_t wp, char_t *path, char_t *query)
|
||||
{
|
||||
char_t *userid, *pass1, *pass2, *group, *enabled, *ok;
|
||||
bool_t bDisable;
|
||||
int nCheck;
|
||||
|
||||
a_assert(wp);
|
||||
|
||||
userid = websGetVar(wp, T("user"), T(""));
|
||||
pass1 = websGetVar(wp, T("password"), T(""));
|
||||
pass2 = websGetVar(wp, T("passconf"), T(""));
|
||||
group = websGetVar(wp, T("group"), T(""));
|
||||
enabled = websGetVar(wp, T("enabled"), T(""));
|
||||
ok = websGetVar(wp, T("ok"), T(""));
|
||||
|
||||
websHeader(wp);
|
||||
websMsgStart(wp);
|
||||
|
||||
if (gstricmp(ok, T("ok")) != 0) {
|
||||
websWrite(wp, T("Add User Cancelled"));
|
||||
} else if (gstrcmp(pass1, pass2) != 0) {
|
||||
websWrite(wp, T("Confirmation Password did not match."));
|
||||
} else {
|
||||
if (enabled && *enabled && (gstrcmp(enabled, T("on")) == 0)) {
|
||||
bDisable = FALSE;
|
||||
} else {
|
||||
bDisable = TRUE;
|
||||
}
|
||||
|
||||
nCheck = umAddUser(userid, pass1, group, 0, bDisable);
|
||||
if (nCheck != 0) {
|
||||
char_t * strError;
|
||||
|
||||
switch (nCheck) {
|
||||
case UM_ERR_DUPLICATE:
|
||||
strError = T("User already exists.");
|
||||
break;
|
||||
|
||||
case UM_ERR_BAD_NAME:
|
||||
strError = T("Invalid user name.");
|
||||
break;
|
||||
|
||||
case UM_ERR_BAD_PASSWORD:
|
||||
strError = T("Invalid password.");
|
||||
break;
|
||||
|
||||
case UM_ERR_NOT_FOUND:
|
||||
strError = T("Invalid or unselected group.");
|
||||
break;
|
||||
|
||||
default:
|
||||
strError = T("Error writing user record.");
|
||||
break;
|
||||
}
|
||||
|
||||
websWrite(wp, T("Unable to add user, \"%s\". %s"),
|
||||
userid, strError);
|
||||
} else {
|
||||
websWrite(wp, T("User, \"%s\" was successfully added."),
|
||||
userid);
|
||||
}
|
||||
}
|
||||
|
||||
websMsgEnd(wp);
|
||||
websFooter(wp);
|
||||
websDone(wp, 200);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Delete a user
|
||||
*/
|
||||
|
||||
static void formDeleteUser(webs_t wp, char_t *path, char_t *query)
|
||||
{
|
||||
char_t *userid, *ok;
|
||||
|
||||
a_assert(wp);
|
||||
|
||||
userid = websGetVar(wp, T("user"), T(""));
|
||||
ok = websGetVar(wp, T("ok"), T(""));
|
||||
|
||||
websHeader(wp);
|
||||
websMsgStart(wp);
|
||||
|
||||
if (gstricmp(ok, T("ok")) != 0) {
|
||||
websWrite(wp, T("Delete User Cancelled"));
|
||||
} else if (umUserExists(userid) == FALSE) {
|
||||
websWrite(wp, T("ERROR: User \"%s\" not found"), userid);
|
||||
} else if (umGetUserProtected(userid)) {
|
||||
websWrite(wp, T("ERROR: User, \"%s\" is delete-protected."), userid);
|
||||
} else if (umDeleteUser(userid) != 0) {
|
||||
websWrite(wp, T("ERROR: Unable to delete user, \"%s\" "), userid);
|
||||
} else {
|
||||
websWrite(wp, T("User, \"%s\" was successfully deleted."), userid);
|
||||
}
|
||||
|
||||
websMsgEnd(wp);
|
||||
websFooter(wp);
|
||||
websDone(wp, 200);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Display the user info
|
||||
*/
|
||||
|
||||
static void formDisplayUser(webs_t wp, char_t *path, char_t *query)
|
||||
{
|
||||
char_t *userid, *ok, *temp;
|
||||
bool_t enabled;
|
||||
|
||||
a_assert(wp);
|
||||
|
||||
userid = websGetVar(wp, T("user"), T(""));
|
||||
ok = websGetVar(wp, T("ok"), T(""));
|
||||
|
||||
websHeader(wp);
|
||||
websWrite(wp, T("<body>"));
|
||||
|
||||
if (gstricmp(ok, T("ok")) != 0) {
|
||||
websWrite(wp, T("Display User Cancelled"));
|
||||
} else if (umUserExists(userid) == FALSE) {
|
||||
websWrite(wp, T("ERROR: User <b>%s</b> not found.\n"), userid);
|
||||
} else {
|
||||
websWrite(wp, T("<h2>User ID: <b>%s</b></h2>\n"), userid);
|
||||
temp = umGetUserGroup(userid);
|
||||
websWrite(wp, T("<h3>User Group: <b>%s</b></h3>\n"), temp);
|
||||
enabled = umGetUserEnabled(userid);
|
||||
websWrite(wp, T("<h3>Enabled: <b>%d</b></h3>\n"), enabled);
|
||||
}
|
||||
|
||||
websWrite(wp, T("</body>\n"));
|
||||
websFooter(wp);
|
||||
websDone(wp, 200);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Generate HTML to create a list box containing the users
|
||||
*/
|
||||
|
||||
static int aspGenerateUserList(int eid, webs_t wp, int argc, char_t **argv)
|
||||
{
|
||||
char_t *userid;
|
||||
int row, nBytesSent, nBytes;
|
||||
|
||||
a_assert(wp);
|
||||
|
||||
nBytes = websWrite(wp,
|
||||
T("<SELECT NAME=\"user\" SIZE=\"3\" TITLE=\"Select a User\">"));
|
||||
row = 0;
|
||||
userid = umGetFirstUser();
|
||||
nBytesSent = 0;
|
||||
|
||||
while (userid && (nBytes > 0)) {
|
||||
nBytes = websWrite(wp, T("<OPTION VALUE=\"%s\">%s\n"),
|
||||
userid, userid);
|
||||
userid = umGetNextUser(userid);
|
||||
nBytesSent += nBytes;
|
||||
}
|
||||
|
||||
nBytesSent += websWrite(wp, T("</SELECT>"));
|
||||
|
||||
return nBytesSent;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Add a group
|
||||
*/
|
||||
|
||||
static void formAddGroup(webs_t wp, char_t *path, char_t *query)
|
||||
{
|
||||
char_t *group, *enabled, *privilege, *method, *ok, *pChar;
|
||||
int nCheck;
|
||||
short priv;
|
||||
accessMeth_t am;
|
||||
bool_t bDisable;
|
||||
|
||||
a_assert(wp);
|
||||
|
||||
group = websGetVar(wp, T("group"), T(""));
|
||||
method = websGetVar(wp, T("method"), T(""));
|
||||
enabled = websGetVar(wp, T("enabled"), T(""));
|
||||
privilege = websGetVar(wp, T("privilege"), T(""));
|
||||
ok = websGetVar(wp, T("ok"), T(""));
|
||||
|
||||
websHeader(wp);
|
||||
websMsgStart(wp);
|
||||
|
||||
if (gstricmp(ok, T("ok")) != 0) {
|
||||
websWrite(wp, T("Add Group Cancelled."));
|
||||
} else if ((group == NULL) || (*group == 0)) {
|
||||
websWrite(wp, T("No Group Name was entered."));
|
||||
} else if (umGroupExists(group)) {
|
||||
websWrite(wp, T("ERROR: Group, \"%s\" already exists."), group);
|
||||
} else {
|
||||
if (privilege && *privilege) {
|
||||
/*
|
||||
* privilege is a mulitple <SELECT> var, and must be parsed.
|
||||
* Values for these variables are space delimited.
|
||||
*/
|
||||
priv = 0;
|
||||
for (pChar = privilege; *pChar; pChar++) {
|
||||
if (*pChar == ' ') {
|
||||
*pChar = '\0';
|
||||
priv |= gatoi(privilege);
|
||||
*pChar = ' ';
|
||||
privilege = pChar + 1;
|
||||
}
|
||||
}
|
||||
priv |= gatoi(privilege);
|
||||
} else {
|
||||
priv = 0;
|
||||
}
|
||||
|
||||
if (method && *method) {
|
||||
am = (accessMeth_t) gatoi(method);
|
||||
} else {
|
||||
am = AM_FULL;
|
||||
}
|
||||
|
||||
if (enabled && *enabled && (gstrcmp(enabled, T("on")) == 0)) {
|
||||
bDisable = FALSE;
|
||||
} else {
|
||||
bDisable = TRUE;
|
||||
}
|
||||
|
||||
nCheck = umAddGroup(group, priv, am, 0, bDisable);
|
||||
if (nCheck != 0) {
|
||||
websWrite(wp, T("Unable to add group, \"%s\", code: %d "),
|
||||
group, nCheck);
|
||||
} else {
|
||||
websWrite(wp, T("Group, \"%s\" was successfully added."),
|
||||
group);
|
||||
}
|
||||
}
|
||||
|
||||
websMsgEnd(wp);
|
||||
websFooter(wp);
|
||||
websDone(wp, 200);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Delete a group
|
||||
*/
|
||||
|
||||
static void formDeleteGroup(webs_t wp, char_t *path, char_t *query)
|
||||
{
|
||||
char_t *group, *ok;
|
||||
|
||||
a_assert(wp);
|
||||
|
||||
group = websGetVar(wp, T("group"), T(""));
|
||||
ok = websGetVar(wp, T("ok"), T(""));
|
||||
|
||||
websHeader(wp);
|
||||
websMsgStart(wp);
|
||||
|
||||
if (gstricmp(ok, T("ok")) != 0) {
|
||||
websWrite(wp, T("Delete Group Cancelled."));
|
||||
} else if ((group == NULL) || (*group == '\0')) {
|
||||
websWrite(wp, T("ERROR: No group was selected."));
|
||||
} else if (umGetGroupProtected(group)) {
|
||||
websWrite(wp, T("ERROR: Group, \"%s\" is delete-protected."), group);
|
||||
} else if (umGetGroupInUse(group)) {
|
||||
websWrite(wp, T("ERROR: Group, \"%s\" is being used."), group);
|
||||
} else if (umDeleteGroup(group) != 0) {
|
||||
websWrite(wp, T("ERROR: Unable to delete group, \"%s\" "), group);
|
||||
} else {
|
||||
websWrite(wp, T("Group, \"%s\" was successfully deleted."), group);
|
||||
}
|
||||
|
||||
websMsgEnd(wp);
|
||||
websFooter(wp);
|
||||
websDone(wp, 200);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Generate HTML to create a list box containing the groups
|
||||
*/
|
||||
|
||||
static int aspGenerateGroupList(int eid, webs_t wp, int argc, char_t **argv)
|
||||
{
|
||||
char_t *group;
|
||||
int row, nBytesSent, nBytes;
|
||||
|
||||
a_assert(wp);
|
||||
|
||||
row = 0;
|
||||
nBytesSent = 0;
|
||||
nBytes = websWrite(wp,
|
||||
T("<SELECT NAME=\"group\" SIZE=\"3\" TITLE=\"Select a Group\">"));
|
||||
/*
|
||||
* Add a special "<NONE>" element to allow de-selection
|
||||
*/
|
||||
nBytes = websWrite(wp, T("<OPTION VALUE=\"\">[NONE]\n"));
|
||||
|
||||
group = umGetFirstGroup();
|
||||
while (group && (nBytes > 0)) {
|
||||
nBytes = websWrite(wp, T("<OPTION VALUE=\"%s\">%s\n"), group, group);
|
||||
group = umGetNextGroup(group);
|
||||
nBytesSent += nBytes;
|
||||
}
|
||||
|
||||
nBytesSent += websWrite(wp, T("</SELECT>"));
|
||||
|
||||
return nBytesSent;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Add an access limit
|
||||
*/
|
||||
|
||||
static void formAddAccessLimit(webs_t wp, char_t *path, char_t *query)
|
||||
{
|
||||
char_t *url, *method, *group, *secure, *ok;
|
||||
int nCheck;
|
||||
accessMeth_t am;
|
||||
short nSecure;
|
||||
|
||||
a_assert(wp);
|
||||
|
||||
url = websGetVar(wp, T("url"), T(""));
|
||||
group = websGetVar(wp, T("group"), T(""));
|
||||
method = websGetVar(wp, T("method"), T(""));
|
||||
secure = websGetVar(wp, T("secure"), T(""));
|
||||
ok = websGetVar(wp, T("ok"), T(""));
|
||||
|
||||
websHeader(wp);
|
||||
websMsgStart(wp);
|
||||
|
||||
if (gstricmp(ok, T("ok")) != 0) {
|
||||
websWrite(wp, T("Add Access Limit Cancelled."));
|
||||
} else if ((url == NULL) || (*url == 0)) {
|
||||
websWrite(wp, T("ERROR: No URL was entered."));
|
||||
} else if (umAccessLimitExists(url)) {
|
||||
websWrite(wp, T("ERROR: An Access Limit for [%s] already exists."),
|
||||
url);
|
||||
} else {
|
||||
if (method && *method) {
|
||||
am = (accessMeth_t) gatoi(method);
|
||||
} else {
|
||||
am = AM_FULL;
|
||||
}
|
||||
|
||||
if (secure && *secure) {
|
||||
nSecure = (short) gatoi(secure);
|
||||
} else {
|
||||
nSecure = 0;
|
||||
}
|
||||
|
||||
nCheck = umAddAccessLimit(url, am, nSecure, group);
|
||||
if (nCheck != 0) {
|
||||
websWrite(wp, T("Unable to add Access Limit for [%s]"), url);
|
||||
} else {
|
||||
websWrite(wp, T("Access limit for [%s], was successfully added."),
|
||||
url);
|
||||
}
|
||||
}
|
||||
|
||||
websMsgEnd(wp);
|
||||
websFooter(wp);
|
||||
websDone(wp, 200);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Delete an Access Limit
|
||||
*/
|
||||
|
||||
static void formDeleteAccessLimit(webs_t wp, char_t *path, char_t *query)
|
||||
{
|
||||
char_t *url, *ok;
|
||||
|
||||
a_assert(wp);
|
||||
|
||||
url = websGetVar(wp, T("url"), T(""));
|
||||
ok = websGetVar(wp, T("ok"), T(""));
|
||||
|
||||
websHeader(wp);
|
||||
websMsgStart(wp);
|
||||
|
||||
if (gstricmp(ok, T("ok")) != 0) {
|
||||
websWrite(wp, T("Delete Access Limit Cancelled"));
|
||||
} else if (umDeleteAccessLimit(url) != 0) {
|
||||
websWrite(wp, T("ERROR: Unable to delete Access Limit for [%s]"),
|
||||
url);
|
||||
} else {
|
||||
websWrite(wp, T("Access Limit for [%s], was successfully deleted."),
|
||||
url);
|
||||
}
|
||||
|
||||
websMsgEnd(wp);
|
||||
websFooter(wp);
|
||||
websDone(wp, 200);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Generate HTML to create a list box containing the access limits
|
||||
*/
|
||||
|
||||
static int aspGenerateAccessLimitList(int eid, webs_t wp,
|
||||
int argc, char_t **argv)
|
||||
{
|
||||
char_t *url;
|
||||
int row, nBytesSent, nBytes;
|
||||
|
||||
a_assert(wp);
|
||||
|
||||
row = nBytesSent = 0;
|
||||
url = umGetFirstAccessLimit();
|
||||
nBytes = websWrite(wp,
|
||||
T("<SELECT NAME=\"url\" SIZE=\"3\" TITLE=\"Select a URL\">"));
|
||||
|
||||
while (url && (nBytes > 0)) {
|
||||
nBytes = websWrite(wp, T("<OPTION VALUE=\"%s\">%s\n"), url, url);
|
||||
url = umGetNextAccessLimit(url);
|
||||
nBytesSent += nBytes;
|
||||
}
|
||||
|
||||
nBytesSent += websWrite(wp, T("</SELECT>"));
|
||||
|
||||
return nBytesSent;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Generate HTML to create a list box containing the access methods
|
||||
*/
|
||||
|
||||
static int aspGenerateAccessMethodList(int eid, webs_t wp,
|
||||
int argc, char_t **argv)
|
||||
{
|
||||
int nBytes;
|
||||
|
||||
a_assert(wp);
|
||||
|
||||
nBytes = websWrite(wp,
|
||||
T("<SELECT NAME=\"method\" SIZE=\"3\" TITLE=\"Select a Method\">"));
|
||||
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">FULL ACCESS\n"),
|
||||
AM_FULL);
|
||||
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">BASIC ACCESS\n"),
|
||||
AM_BASIC);
|
||||
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\" SELECTED>DIGEST ACCESS\n"),
|
||||
AM_DIGEST);
|
||||
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">NO ACCESS\n"),
|
||||
AM_NONE);
|
||||
nBytes += websWrite(wp, T("</SELECT>"));
|
||||
|
||||
return nBytes;
|
||||
}
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Generate HTML to create a list box containing privileges
|
||||
*/
|
||||
|
||||
static int aspGeneratePrivilegeList(int eid, webs_t wp,
|
||||
int argc, char_t **argv)
|
||||
{
|
||||
int nBytes;
|
||||
|
||||
a_assert(wp);
|
||||
|
||||
nBytes = websWrite(wp, T("<SELECT NAME=\"privilege\" SIZE=\"3\" "));
|
||||
nBytes += websWrite(wp, T("MULTIPLE TITLE=\"Choose Privileges\">"));
|
||||
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">READ\n"), PRIV_READ);
|
||||
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">EXECUTE\n"), PRIV_WRITE);
|
||||
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">ADMINISTRATE\n"),
|
||||
PRIV_ADMIN);
|
||||
nBytes += websWrite(wp, T("</SELECT>"));
|
||||
|
||||
return nBytes;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Save the user management configuration to a file
|
||||
*/
|
||||
|
||||
static void formSaveUserManagement(webs_t wp, char_t *path, char_t *query)
|
||||
{
|
||||
char_t *ok;
|
||||
|
||||
a_assert(wp);
|
||||
|
||||
ok = websGetVar(wp, T("ok"), T(""));
|
||||
|
||||
websHeader(wp);
|
||||
websMsgStart(wp);
|
||||
|
||||
if (gstricmp(ok, T("ok")) != 0) {
|
||||
websWrite(wp, T("Save Cancelled."));
|
||||
} else if (umCommit(NULL) != 0) {
|
||||
websWrite(wp, T("ERROR: Unable to save user configuration."));
|
||||
} else {
|
||||
websWrite(wp, T("User configuration was saved successfully."));
|
||||
}
|
||||
|
||||
websMsgEnd(wp);
|
||||
websFooter(wp);
|
||||
websDone(wp, 200);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Load the user management configuration from a file
|
||||
*/
|
||||
|
||||
static void formLoadUserManagement(webs_t wp, char_t *path, char_t *query)
|
||||
{
|
||||
char_t *ok;
|
||||
|
||||
a_assert(wp);
|
||||
|
||||
ok = websGetVar(wp, T("ok"), T(""));
|
||||
|
||||
websHeader(wp);
|
||||
websMsgStart(wp);
|
||||
|
||||
if (gstricmp(ok, T("ok")) != 0) {
|
||||
websWrite(wp, T("Load Cancelled."));
|
||||
} else if (umRestore(NULL) != 0) {
|
||||
websWrite(wp, T("ERROR: Unable to load user configuration."));
|
||||
} else {
|
||||
websWrite(wp, T("User configuration was re-loaded successfully."));
|
||||
}
|
||||
|
||||
websMsgEnd(wp);
|
||||
websFooter(wp);
|
||||
websDone(wp, 200);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Message start and end convenience functions
|
||||
*/
|
||||
|
||||
static void websMsgStart(webs_t wp)
|
||||
{
|
||||
websWrite(wp, MSG_START);
|
||||
}
|
||||
|
||||
static void websMsgEnd(webs_t wp)
|
||||
{
|
||||
websWrite(wp, MSG_END);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,212 +0,0 @@
|
||||
/*
|
||||
* url.c -- Parse URLs
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* This module parses URLs into their components.
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#include "wsIntrn.h"
|
||||
|
||||
/********************************* Statics ************************************/
|
||||
/*
|
||||
* htmExt is declared in this way to avoid a Linux and Solaris segmentation
|
||||
* fault when a constant string is passed to strlower which could change its
|
||||
* argument.
|
||||
*/
|
||||
|
||||
char_t htmExt[] = T(".htm");
|
||||
|
||||
|
||||
/*********************************** Code *************************************/
|
||||
/*
|
||||
* Return the mime type for the given URL given a URL.
|
||||
* The caller supplies the buffer to hold the result.
|
||||
* charCnt is the number of characters the buffer will hold, ascii or UNICODE.
|
||||
*/
|
||||
|
||||
char_t *websUrlType(char_t *url, char_t *buf, int charCnt)
|
||||
{
|
||||
sym_t *sp;
|
||||
char_t *ext, *parsebuf;
|
||||
|
||||
a_assert(url && *url);
|
||||
a_assert(buf && charCnt > 0);
|
||||
|
||||
if (url == NULL || *url == '\0') {
|
||||
gstrcpy(buf, T("text/plain"));
|
||||
return buf;
|
||||
}
|
||||
if (websUrlParse(url, &parsebuf, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, &ext) < 0) {
|
||||
gstrcpy(buf, T("text/plain"));
|
||||
return buf;
|
||||
}
|
||||
strlower(ext);
|
||||
|
||||
/*
|
||||
* Lookup the mime type symbol table to find the relevant content type
|
||||
*/
|
||||
if ((sp = symLookup(websMime, ext)) != NULL) {
|
||||
gstrncpy(buf, sp->content.value.string, charCnt);
|
||||
} else {
|
||||
gstrcpy(buf, T("text/plain"));
|
||||
}
|
||||
bfree(B_L, parsebuf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Parse the URL. A buffer is allocated to store the parsed URL in *pbuf.
|
||||
* This must be freed by the caller. NOTE: tag is not yet fully supported.
|
||||
*/
|
||||
|
||||
int websUrlParse(char_t *url, char_t **pbuf, char_t **phost, char_t **ppath,
|
||||
char_t **pport, char_t **pquery, char_t **pproto, char_t **ptag,
|
||||
char_t **pext)
|
||||
{
|
||||
char_t *tok, *cp, *host, *path, *port, *proto, *tag, *query, *ext;
|
||||
char_t *last_delim, *hostbuf, *portbuf, *buf;
|
||||
int c, len, ulen;
|
||||
|
||||
a_assert(url);
|
||||
a_assert(pbuf);
|
||||
|
||||
ulen = gstrlen(url);
|
||||
/*
|
||||
* We allocate enough to store separate hostname and port number fields.
|
||||
* As there are 3 strings in the one buffer, we need room for 3 null chars.
|
||||
* We allocate MAX_PORT_LEN char_t's for the port number.
|
||||
*/
|
||||
len = ulen * 2 + MAX_PORT_LEN + 3;
|
||||
if ((buf = balloc(B_L, len * sizeof(char_t))) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
portbuf = &buf[len - MAX_PORT_LEN - 1];
|
||||
hostbuf = &buf[ulen+1];
|
||||
gstrcpy(buf, url);
|
||||
url = buf;
|
||||
|
||||
/*
|
||||
* Convert the current listen port to a string. We use this if the URL has
|
||||
* no explicit port setting
|
||||
*/
|
||||
stritoa(websGetPort(), portbuf, MAX_PORT_LEN);
|
||||
port = portbuf;
|
||||
path = T("/");
|
||||
proto = T("http");
|
||||
host = T("localhost");
|
||||
query = T("");
|
||||
ext = htmExt;
|
||||
tag = T("");
|
||||
|
||||
if (gstrncmp(url, T("http://"), 7) == 0) {
|
||||
tok = &url[7];
|
||||
tok[-3] = '\0';
|
||||
proto = url;
|
||||
host = tok;
|
||||
for (cp = tok; *cp; cp++) {
|
||||
if (*cp == '/') {
|
||||
break;
|
||||
}
|
||||
if (*cp == ':') {
|
||||
*cp++ = '\0';
|
||||
port = cp;
|
||||
tok = cp;
|
||||
}
|
||||
}
|
||||
if ((cp = gstrchr(tok, '/')) != NULL) {
|
||||
/*
|
||||
* If a full URL is supplied, we need to copy the host and port
|
||||
* portions into static buffers.
|
||||
*/
|
||||
c = *cp;
|
||||
*cp = '\0';
|
||||
gstrncpy(hostbuf, host, ulen);
|
||||
gstrncpy(portbuf, port, MAX_PORT_LEN);
|
||||
*cp = c;
|
||||
host = hostbuf;
|
||||
port = portbuf;
|
||||
path = cp;
|
||||
tok = cp;
|
||||
}
|
||||
|
||||
} else {
|
||||
path = url;
|
||||
tok = url;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the query string
|
||||
*/
|
||||
if ((cp = gstrchr(tok, '?')) != NULL) {
|
||||
*cp++ = '\0';
|
||||
query = cp;
|
||||
path = tok;
|
||||
tok = query;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the fragment identifier
|
||||
*/
|
||||
if ((cp = gstrchr(tok, '#')) != NULL) {
|
||||
*cp++ = '\0';
|
||||
if (*query == 0) {
|
||||
path = tok;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Only do the following if asked for the extension
|
||||
*/
|
||||
if (pext) {
|
||||
if ((cp = gstrrchr(path, '.')) != NULL) {
|
||||
if ((last_delim = gstrrchr(path, '/')) != NULL) {
|
||||
if (last_delim > cp) {
|
||||
ext = htmExt;
|
||||
} else {
|
||||
ext = cp;
|
||||
}
|
||||
} else {
|
||||
ext = cp;
|
||||
}
|
||||
} else {
|
||||
if (path[gstrlen(path) - 1] == '/') {
|
||||
ext = htmExt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass back the fields requested (if not NULL)
|
||||
*/
|
||||
if (phost)
|
||||
*phost = host;
|
||||
if (ppath)
|
||||
*ppath = path;
|
||||
if (pport)
|
||||
*pport = port;
|
||||
if (pproto)
|
||||
*pproto = proto;
|
||||
if (pquery)
|
||||
*pquery = query;
|
||||
if (ptag)
|
||||
*ptag = tag;
|
||||
if (pext)
|
||||
*pext = ext;
|
||||
*pbuf = buf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
* base64.c -- Base64 Mime encoding
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* The base64 command encodes and decodes a string in mime base64 format
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#include "wsIntrn.h"
|
||||
|
||||
/******************************** Local Data **********************************/
|
||||
/*
|
||||
* Mapping of ANSI chars to base64 Mime encoding alphabet (see below)
|
||||
*/
|
||||
|
||||
static char_t map64[] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
|
||||
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
};
|
||||
|
||||
static char_t alphabet64[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||||
'4', '5', '6', '7', '8', '9', '+', '/',
|
||||
};
|
||||
|
||||
/*********************************** Code *************************************/
|
||||
/*
|
||||
* Decode a buffer from "string" and into "outbuf"
|
||||
*/
|
||||
|
||||
int websDecode64(char_t *outbuf, char_t *string, int outlen)
|
||||
{
|
||||
unsigned long shiftbuf;
|
||||
char_t *cp, *op;
|
||||
int c, i, j, shift;
|
||||
|
||||
op = outbuf;
|
||||
*op = '\0';
|
||||
cp = string;
|
||||
while (*cp && *cp != '=') {
|
||||
/*
|
||||
* Map 4 (6bit) input bytes and store in a single long (shiftbuf)
|
||||
*/
|
||||
shiftbuf = 0;
|
||||
shift = 18;
|
||||
for (i = 0; i < 4 && *cp && *cp != '='; i++, cp++) {
|
||||
c = map64[*cp & 0xff];
|
||||
if (c == -1) {
|
||||
error(E_L, E_LOG, T("Bad string: %s at %c index %d"), string,
|
||||
c, i);
|
||||
return -1;
|
||||
}
|
||||
shiftbuf = shiftbuf | (c << shift);
|
||||
shift -= 6;
|
||||
}
|
||||
/*
|
||||
* Interpret as 3 normal 8 bit bytes (fill in reverse order).
|
||||
* Check for potential buffer overflow before filling.
|
||||
*/
|
||||
--i;
|
||||
if ((op + i) >= &outbuf[outlen]) {
|
||||
gstrcpy(outbuf, T("String too big"));
|
||||
return -1;
|
||||
}
|
||||
for (j = 0; j < i; j++) {
|
||||
*op++ = (char_t) ((shiftbuf >> (8 * (2 - j))) & 0xff);
|
||||
}
|
||||
*op = '\0';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Encode a buffer from "string" into "outbuf"
|
||||
*/
|
||||
|
||||
void websEncode64(char_t *outbuf, char_t *string, int outlen)
|
||||
{
|
||||
unsigned long shiftbuf;
|
||||
char_t *cp, *op;
|
||||
int x, i, j, shift;
|
||||
|
||||
op = outbuf;
|
||||
*op = '\0';
|
||||
cp = string;
|
||||
while (*cp) {
|
||||
/*
|
||||
* Take three characters and create a 24 bit number in shiftbuf
|
||||
*/
|
||||
shiftbuf = 0;
|
||||
for (j = 2; j >= 0 && *cp; j--, cp++) {
|
||||
shiftbuf |= ((*cp & 0xff) << (j * 8));
|
||||
}
|
||||
/*
|
||||
* Now convert shiftbuf to 4 base64 letters. The i,j magic calculates
|
||||
* how many letters need to be output.
|
||||
*/
|
||||
shift = 18;
|
||||
for (i = ++j; i < 4 && op < &outbuf[outlen] ; i++) {
|
||||
x = (shiftbuf >> shift) & 0x3f;
|
||||
*op++ = alphabet64[(shiftbuf >> shift) & 0x3f];
|
||||
shift -= 6;
|
||||
}
|
||||
/*
|
||||
* Pad at the end with '='
|
||||
*/
|
||||
while (j-- > 0) {
|
||||
*op++ = '=';
|
||||
}
|
||||
*op = '\0';
|
||||
}
|
||||
}
|
||||
/******************************************************************************/
|
||||
@@ -1,188 +0,0 @@
|
||||
/*
|
||||
* webcomp -- Compile web pages into C source
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* Usage: webcomp prefix filelist >webrom.c
|
||||
*
|
||||
* filelist is a file containing the pathnames of all web pages
|
||||
* prefix is a path prefix to remove from all the web page pathnames
|
||||
* webrom.c is the resulting C source file to compile and link.
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#include "wsIntrn.h"
|
||||
|
||||
/**************************** Forward Declarations ****************************/
|
||||
|
||||
static int compile(char_t *fileList, char_t *prefix);
|
||||
static void usage();
|
||||
|
||||
/*********************************** Code *************************************/
|
||||
/*
|
||||
* Main program for webpack test harness
|
||||
*/
|
||||
|
||||
int gmain(int argc, char_t* argv[])
|
||||
{
|
||||
char_t *fileList, *prefix;
|
||||
|
||||
fileList = NULL;
|
||||
|
||||
if (argc != 3) {
|
||||
usage();
|
||||
}
|
||||
|
||||
prefix = argv[1];
|
||||
fileList = argv[2];
|
||||
|
||||
if (compile(fileList, prefix) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Output usage message
|
||||
*/
|
||||
|
||||
static void usage()
|
||||
{
|
||||
fprintf(stderr, "usage: webcomp prefix filelist >output.c\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Compile the web pages
|
||||
*/
|
||||
|
||||
static int compile(char_t *fileList, char_t *prefix)
|
||||
{
|
||||
gstat_t sbuf;
|
||||
FILE *lp;
|
||||
time_t now;
|
||||
char_t file[FNAMESIZE];
|
||||
char_t *cp, *sl;
|
||||
char buf[512];
|
||||
unsigned char *p;
|
||||
int j, i, len, fd, nFile;
|
||||
|
||||
/*
|
||||
* Open list of files
|
||||
*/
|
||||
if ((lp = fopen(fileList, "r")) == NULL) {
|
||||
fprintf(stderr, "Can't open file list %s\n", fileList);
|
||||
return -1;
|
||||
}
|
||||
|
||||
time(&now);
|
||||
fprintf(stdout, "/*\n * webrom.c -- Compiled Web Pages\n *\n");
|
||||
fprintf(stdout, " * Compiled by GoAhead WebCompile: %s */\n\n",
|
||||
gctime(&now));
|
||||
fprintf(stdout, "#include \"wsIntrn.h\"\n\n");
|
||||
fprintf(stdout, "#ifndef WEBS_PAGE_ROM\n");
|
||||
fprintf(stdout, "websRomPageIndexType websRomPageIndex[] = {\n");
|
||||
fprintf(stdout, " { 0, 0, 0 },\n};\n");
|
||||
fprintf(stdout, "#else\n");
|
||||
|
||||
/*
|
||||
* Open each input file and compile each web page
|
||||
*/
|
||||
nFile = 0;
|
||||
while (fgets(file, sizeof(file), lp) != NULL) {
|
||||
if ((p = strchr(file, '\n')) || (p = strchr(file, '\r'))) {
|
||||
*p = '\0';
|
||||
}
|
||||
if (*file == '\0') {
|
||||
continue;
|
||||
}
|
||||
if (gstat(file, &sbuf) == 0 && sbuf.st_mode & S_IFDIR) {
|
||||
continue;
|
||||
}
|
||||
if ((fd = gopen(file, O_RDONLY | O_BINARY)) < 0) {
|
||||
fprintf(stderr, "Can't open file %s\n", file);
|
||||
return -1;
|
||||
}
|
||||
fprintf(stdout, "static unsigned char page_%d[] = {\n", nFile);
|
||||
|
||||
while ((len = read(fd, buf, sizeof(buf))) > 0) {
|
||||
p = buf;
|
||||
for (i = 0; i < len; ) {
|
||||
fprintf(stdout, " ");
|
||||
for (j = 0; p < &buf[len] && j < 16; j++, p++) {
|
||||
fprintf(stdout, "%3d,", *p);
|
||||
}
|
||||
i += j;
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
}
|
||||
fprintf(stdout, " 0 };\n\n");
|
||||
|
||||
close(fd);
|
||||
nFile++;
|
||||
}
|
||||
fclose(lp);
|
||||
|
||||
/*
|
||||
* Now output the page index
|
||||
*/
|
||||
fprintf(stdout, "websRomPageIndexType websRomPageIndex[] = {\n");
|
||||
|
||||
if ((lp = fopen(fileList, "r")) == NULL) {
|
||||
fprintf(stderr, "Can't open file list %s\n", fileList);
|
||||
return -1;
|
||||
}
|
||||
nFile = 0;
|
||||
while (fgets(file, sizeof(file), lp) != NULL) {
|
||||
if ((p = strchr(file, '\n')) || (p = strchr(file, '\r'))) {
|
||||
*p = '\0';
|
||||
}
|
||||
if (*file == '\0') {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Remove the prefix and add a leading "/" when we print the path
|
||||
*/
|
||||
if (strncmp(file, prefix, gstrlen(prefix)) == 0) {
|
||||
cp = &file[gstrlen(prefix)];
|
||||
} else {
|
||||
cp = file;
|
||||
}
|
||||
while((sl = strchr(file, '\\')) != NULL) {
|
||||
*sl = '/';
|
||||
}
|
||||
if (*cp == '/') {
|
||||
cp++;
|
||||
}
|
||||
|
||||
if (gstat(file, &sbuf) == 0 && sbuf.st_mode & S_IFDIR) {
|
||||
fprintf(stdout, " { T(\"/%s\"), 0, 0 },\n", cp);
|
||||
continue;
|
||||
}
|
||||
fprintf(stdout, " { T(\"/%s\"), page_%d, %d },\n", cp, nFile,
|
||||
sbuf.st_size);
|
||||
nFile++;
|
||||
}
|
||||
fclose(lp);
|
||||
|
||||
fprintf(stdout, " { 0, 0, 0 },\n");
|
||||
fprintf(stdout, "};\n");
|
||||
fprintf(stdout, "#endif /* WEBS_PAGE_ROM */\n");
|
||||
|
||||
fclose(lp);
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,499 +0,0 @@
|
||||
/*
|
||||
* main.c -- Main program for the GoAhead WebServer (RTEMS version)
|
||||
*
|
||||
* Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* Main program for for the GoAhead WebServer. This is a demonstration
|
||||
* main program to initialize and configure the web server.
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#include "uemf.h"
|
||||
#include "wsIntrn.h"
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/error.h>
|
||||
|
||||
#ifdef WEBS_SSL_SUPPORT
|
||||
#include "websSSL.h"
|
||||
#endif
|
||||
|
||||
#ifdef USER_MANAGEMENT_SUPPORT
|
||||
#include "um.h"
|
||||
void formDefineUserMgmt(void);
|
||||
#endif
|
||||
|
||||
/*********************************** Locals ***********************************/
|
||||
/*
|
||||
* Change configuration here
|
||||
*/
|
||||
|
||||
extern const char *tftpServer;
|
||||
/* static char_t *rootWeb = T("goahead"); * Root web directory */
|
||||
static char_t *password = T(""); /* Security password */
|
||||
static int port = 80; /* Server port */
|
||||
static int retries = 5; /* Server port retries */
|
||||
static int finished; /* Finished flag */
|
||||
|
||||
/*
|
||||
* Structure to hold timer events
|
||||
*/
|
||||
typedef struct {
|
||||
void (*routine)(long arg); /* Timer routine */
|
||||
long arg; /* Argument to routine */
|
||||
} websTimer_t;
|
||||
|
||||
/* The following holds the pointer to an allocated websTimer_t structure .
|
||||
* Using this method only one timer can be active at a time, but
|
||||
* for the WebServer, this should be OK.
|
||||
*/
|
||||
websTimer_t *tp;
|
||||
|
||||
/****************************** Forward Declarations **************************/
|
||||
|
||||
static int initWebs();
|
||||
static int aspTest(int eid, webs_t wp, int argc, char_t **argv);
|
||||
static void formTest(webs_t wp, char_t *path, char_t *query);
|
||||
static int websHomePageHandler(webs_t wp, char_t *urlPrefix, char_t *webDir,
|
||||
int arg, char_t* url, char_t* path, char_t* query);
|
||||
static void timerProc(int signo);
|
||||
#if B_STATS
|
||||
static void printMemStats(int handle, char_t *fmt, ...);
|
||||
static void memLeaks();
|
||||
#endif
|
||||
static timer_t timer_id;
|
||||
static void rtems_httpd_daemon();
|
||||
|
||||
/*********************************** Code *************************************/
|
||||
/*
|
||||
* Main -- entry point from RTEMS
|
||||
*/
|
||||
int rtems_initialize_webserver()
|
||||
{
|
||||
rtems_status_code sc;
|
||||
rtems_id tid;
|
||||
int priority;
|
||||
|
||||
/***********************************************************************
|
||||
* Default HTTPD priority.
|
||||
**********************************************************************/
|
||||
priority = 40;
|
||||
|
||||
sc = rtems_task_create(rtems_build_name('H', 'T', 'P', 'D'),
|
||||
priority, 8*1024,
|
||||
RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR |
|
||||
RTEMS_INTERRUPT_LEVEL(0),
|
||||
RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
|
||||
&tid);
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
{
|
||||
return(RTEMS_UNSATISFIED);
|
||||
}
|
||||
|
||||
sc = rtems_task_start(tid, rtems_httpd_daemon, 0);
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
{
|
||||
return(RTEMS_UNSATISFIED);
|
||||
}
|
||||
|
||||
return(RTEMS_SUCCESSFUL);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
rtems_httpd_daemon()
|
||||
{
|
||||
/*
|
||||
* Initialize the memory allocator. Allow use of malloc and start with a
|
||||
* 10K heap.
|
||||
*/
|
||||
bopen(NULL, (10 * 1024), B_USE_MALLOC);
|
||||
|
||||
/*
|
||||
* Initialize the web server
|
||||
*/
|
||||
if (initWebs() < 0) {
|
||||
rtems_panic("Unable to initialize Web server !!\n");
|
||||
}
|
||||
|
||||
#ifdef WEBS_SSL_SUPPORT
|
||||
websSSLOpen();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Basic event loop. SocketReady returns true when a socket is ready for
|
||||
* service. SocketSelect will block until an event occurs. SocketProcess
|
||||
* will actually do the servicing.
|
||||
*/
|
||||
while (!finished) {
|
||||
if (socketReady(-1) || socketSelect(-1, 2000)) {
|
||||
socketProcess(-1);
|
||||
}
|
||||
/*websCgiCleanup();*/
|
||||
emfSchedProcess();
|
||||
}
|
||||
|
||||
#ifdef WEBS_SSL_SUPPORT
|
||||
websSSLClose();
|
||||
#endif
|
||||
|
||||
#ifdef USER_MANAGEMENT_SUPPORT
|
||||
umClose();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Close the socket module, report memory leaks and close the memory allocator
|
||||
*/
|
||||
websCloseServer();
|
||||
websDefaultClose();
|
||||
socketClose();
|
||||
symSubClose();
|
||||
#if B_STATS
|
||||
memLeaks();
|
||||
#endif
|
||||
bclose();
|
||||
rtems_task_delete( RTEMS_SELF );
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Initialize the web server.
|
||||
*/
|
||||
|
||||
static int initWebs()
|
||||
{
|
||||
struct hostent* hp;
|
||||
struct in_addr intaddr;
|
||||
char host[128], webdir[128];
|
||||
char_t wbuf[128];
|
||||
|
||||
/*
|
||||
* Initialize the socket subsystem
|
||||
*/
|
||||
socketOpen();
|
||||
|
||||
/*
|
||||
* Define the local Ip address, host name, default home page and the
|
||||
* root web directory.
|
||||
*/
|
||||
if (gethostname(host, sizeof(host)) < 0) {
|
||||
error(E_L, E_LOG, T("Can't get hostname"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* intaddr.s_addr = (unsigned long) hostGetByName(host); */
|
||||
if ((hp = gethostbyname(host)) == NULL) {
|
||||
error(E_L, E_LOG, T("Can't get host address"));
|
||||
return -1;
|
||||
}
|
||||
memcpy((char *) &intaddr, (char *) hp->h_addr_list[0],
|
||||
(size_t) hp->h_length);
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Set /TFTP/x.y.z.w/goahead as the root web. Modify to suit your needs
|
||||
*/
|
||||
sprintf(webdir, "/TFTP/%s/%s", tftpServer, rootWeb);
|
||||
#else
|
||||
sprintf(webdir, "/");
|
||||
#endif
|
||||
/*
|
||||
* Configure the web server options before opening the web server
|
||||
*/
|
||||
websSetDefaultDir(webdir);
|
||||
ascToUni(wbuf, inet_ntoa(intaddr), sizeof(wbuf));
|
||||
websSetIpaddr(wbuf);
|
||||
ascToUni(wbuf, host, sizeof(wbuf));
|
||||
websSetHost(wbuf);
|
||||
|
||||
/*
|
||||
* Configure the web server options before opening the web server
|
||||
*/
|
||||
#if 0
|
||||
websSetDefaultPage(T("default.asp"));
|
||||
#else
|
||||
websSetDefaultPage(T("index.html"));
|
||||
#endif
|
||||
websSetPassword(password);
|
||||
|
||||
/*
|
||||
* Open the web server on the given port. If that port is taken, try
|
||||
* the next sequential port for up to "retries" attempts.
|
||||
*/
|
||||
websOpenServer(port, retries);
|
||||
|
||||
/*
|
||||
* First create the URL handlers. Note: handlers are called in sorted order
|
||||
* with the longest path handler examined first. Here we define the security
|
||||
* handler, forms handler and the default web page handler.
|
||||
*/
|
||||
websUrlHandlerDefine(T(""), NULL, 0, websSecurityHandler,
|
||||
WEBS_HANDLER_FIRST);
|
||||
websUrlHandlerDefine(T("/goform"), NULL, 0, websFormHandler, 0);
|
||||
websUrlHandlerDefine(T(""), NULL, 0, websDefaultHandler,
|
||||
WEBS_HANDLER_LAST);
|
||||
|
||||
/*
|
||||
* Now define two test procedures. Replace these with your application
|
||||
* relevant ASP script procedures and form functions.
|
||||
*/
|
||||
websAspDefine(T("aspTest"), aspTest);
|
||||
websFormDefine(T("formTest"), formTest);
|
||||
|
||||
/*
|
||||
* Create a handler for the default home page
|
||||
*/
|
||||
websUrlHandlerDefine(T("/"), NULL, 0, websHomePageHandler, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Test Javascript binding for ASP. This will be invoked when "aspTest" is
|
||||
* embedded in an ASP page. See web/asp.asp for usage. Set browser to
|
||||
* "localhost/asp.asp" to test.
|
||||
*/
|
||||
|
||||
static int aspTest(int eid, webs_t wp, int argc, char_t **argv)
|
||||
{
|
||||
char_t *name, *address;
|
||||
|
||||
if (ejArgs(argc, argv, T("%s %s"), &name, &address) < 2) {
|
||||
websError(wp, 400, T("Insufficient args\n"));
|
||||
return -1;
|
||||
}
|
||||
return websWrite(wp, T("Name: %s, Address %s"), name, address);
|
||||
}
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Test form for posted data (in-memory CGI). This will be called when the
|
||||
* form in web/asp.asp is invoked. Set browser to "localhost/asp.asp" to test.
|
||||
*/
|
||||
|
||||
static void formTest(webs_t wp, char_t *path, char_t *query)
|
||||
{
|
||||
char_t *name, *address;
|
||||
|
||||
name = websGetVar(wp, T("name"), T("Joe Smith"));
|
||||
address = websGetVar(wp, T("address"), T("1212 Milky Way Ave."));
|
||||
|
||||
websHeader(wp);
|
||||
websWrite(wp, T("<body><h2>Name: %s, Address: %s</h2>\n"), name, address);
|
||||
websFooter(wp);
|
||||
websDone(wp, 200);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Create a timer to invoke the routine in "delay" milliseconds.
|
||||
*/
|
||||
|
||||
void *emfCreateTimer(int delay, void (*routine)(long arg), long arg)
|
||||
{
|
||||
/* this variable is only used in the if'ed 0 section below */
|
||||
#if 0
|
||||
struct sigaction act;
|
||||
#endif
|
||||
struct itimerspec its = { {0,0}, {0,0} };
|
||||
struct sigevent se;
|
||||
int status;
|
||||
|
||||
if ((tp = balloc(B_L, sizeof(websTimer_t)))) {
|
||||
tp->routine = routine;
|
||||
tp->arg = arg;
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
se.sigev_notify = SIGEV_THREAD;
|
||||
se.sigev_value.sival_ptr = tp;
|
||||
se.sigev_notify_function = (void (*)(union sigval)) timerProc;
|
||||
|
||||
/*
|
||||
* NOT POSIX?
|
||||
* se.sigev_notify_attributes = NULL;
|
||||
*/
|
||||
|
||||
|
||||
status = timer_create(CLOCK_REALTIME, &se, &timer_id);
|
||||
if (status != 0) {
|
||||
bfree(B_L, tp);
|
||||
return NULL;
|
||||
}
|
||||
/* convert delay millisecs to secs and usecs required by struct */
|
||||
its.it_value.tv_sec = delay / 1000;
|
||||
its.it_value.tv_nsec = (delay % 1000) * 1000000;
|
||||
|
||||
status = timer_settime(timer_id, 0, &its, 0);
|
||||
if (status != 0) {
|
||||
bfree(B_L, tp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
act.sa_flags = 0;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_handler = timerProc;
|
||||
sigaction(SIGALRM, &act, NULL);
|
||||
|
||||
/* convert delay millisecs to secs and usecs required by struct */
|
||||
its.it_value.tv_sec = delay / 1000;
|
||||
its.it_value.tv_usec = (delay % 1000) * 1000;
|
||||
|
||||
if (setitimer(ITIMER_REAL, &its, NULL) == -1) {
|
||||
bfree(B_L, tp);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
return tp;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Delete a timer
|
||||
*/
|
||||
|
||||
void emfDeleteTimer(void * id)
|
||||
{
|
||||
websTimer_t *wtp;
|
||||
/*struct itimerval its = { {0,0}, {0,0} };*/
|
||||
|
||||
wtp = (websTimer_t *)id;
|
||||
/* setitimer(ITIMER_REAL, &its, NULL);*/
|
||||
timer_delete(timer_id);
|
||||
bfree(B_L, wtp);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Timer handler
|
||||
*/
|
||||
|
||||
static void timerProc(int signo)
|
||||
{
|
||||
websTimer_t wtp = *tp;
|
||||
|
||||
/* Copy the timer structure to a local first and delete it before calling
|
||||
* the function, since the function could create another timer. In this
|
||||
* implementation, only one timer can be allocated at a time.
|
||||
*/
|
||||
|
||||
bfree(B_L, tp);
|
||||
(wtp.routine)(wtp.arg);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Home page handler
|
||||
*/
|
||||
|
||||
static int websHomePageHandler(webs_t wp, char_t *urlPrefix, char_t *webDir,
|
||||
int arg, char_t* url, char_t* path, char_t* query)
|
||||
{
|
||||
/*
|
||||
* If the empty or "/" URL is invoked, redirect default URLs to the home page
|
||||
*/
|
||||
if (*url == '\0' || gstrcmp(url, T("/")) == 0) {
|
||||
#if 0
|
||||
websRedirect(wp, T("home.asp"));
|
||||
#else
|
||||
websRedirect(wp, T("index.html"));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#if B_STATS
|
||||
static void memLeaks()
|
||||
{
|
||||
int fd=1;
|
||||
|
||||
/* if ((fd = gopen(T("leak.txt"), O_CREAT | O_TRUNC | O_WRONLY)) >= 0) { */
|
||||
bstats(fd, printMemStats);
|
||||
/*
|
||||
close(fd);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Print memory usage / leaks
|
||||
*/
|
||||
|
||||
static void printMemStats(int handle, char_t *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char_t buf[256];
|
||||
|
||||
va_start(args, fmt);
|
||||
vsprintf(buf, fmt, args);
|
||||
va_end(args);
|
||||
write(handle, buf, strlen(buf));
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* Default error handler. The developer should insert code to handle
|
||||
* error messages in the desired manner.
|
||||
*/
|
||||
|
||||
void defaultErrorHandler(int etype, char_t *msg)
|
||||
{
|
||||
#if 1
|
||||
write(1, msg, gstrlen(msg));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* Trace log. Customize this function to log trace output
|
||||
*/
|
||||
|
||||
void defaultTraceHandler(int level, char_t *buf)
|
||||
{
|
||||
/*
|
||||
* The following code would write all trace regardless of level
|
||||
* to stdout.
|
||||
*/
|
||||
#if 1
|
||||
if (buf) {
|
||||
write(1, buf, gstrlen(buf));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* Returns a pointer to an allocated qualified unique temporary file name.
|
||||
* This filename must eventually be deleted with bfree();
|
||||
*/
|
||||
|
||||
char_t *websGetCgiCommName()
|
||||
{
|
||||
char_t *pname1, *pname2;
|
||||
|
||||
pname1 = tempnam(NULL, T("cgi"));
|
||||
pname2 = bstrdup(B_L, pname1);
|
||||
free(pname1);
|
||||
return pname2;
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
* Page.c -- Support for page retrieval.
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* This module provides page retrieval handling. It provides support for
|
||||
* reading web pages from file systems and has expansion for ROMed web
|
||||
* pages.
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#include "wsIntrn.h"
|
||||
|
||||
/*********************************** Code *************************************/
|
||||
/*
|
||||
* Open a web page. lpath is the local filename. path is the URL path name.
|
||||
*/
|
||||
|
||||
int websPageOpen(webs_t wp, char_t *lpath, char_t *path, int mode, int perm)
|
||||
{
|
||||
a_assert(websValid(wp));
|
||||
|
||||
#ifdef WEBS_PAGE_ROM
|
||||
return websRomPageOpen(wp, path, mode, perm);
|
||||
#else
|
||||
return (wp->docfd = gopen(lpath, mode, perm));
|
||||
#endif /* WEBS_PAGE_ROM */
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Close a web page
|
||||
*/
|
||||
|
||||
void websPageClose(webs_t wp)
|
||||
{
|
||||
a_assert(websValid(wp));
|
||||
|
||||
#ifdef WEBS_PAGE_ROM
|
||||
websRomPageClose(wp->docfd);
|
||||
#else
|
||||
if (wp->docfd >= 0) {
|
||||
close(wp->docfd);
|
||||
wp->docfd = -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Stat a web page lpath is the local filename. path is the URL path name.
|
||||
*/
|
||||
|
||||
int websPageStat(webs_t wp, char_t *lpath, char_t *path, websStatType* sbuf)
|
||||
{
|
||||
#ifdef WEBS_PAGE_ROM
|
||||
return websRomPageStat(path, sbuf);
|
||||
#else
|
||||
gstat_t s;
|
||||
|
||||
if (gstat(lpath, &s) < 0) {
|
||||
return -1;
|
||||
}
|
||||
sbuf->size = s.st_size;
|
||||
sbuf->mtime = s.st_mtime;
|
||||
sbuf->isDir = s.st_mode & S_IFDIR;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Is this file a directory?
|
||||
*/
|
||||
|
||||
int websPageIsDirectory(char_t *lpath)
|
||||
{
|
||||
#ifdef WEBS_PAGE_ROM
|
||||
websStatType sbuf;
|
||||
|
||||
if (websRomPageStat(lpath, &sbuf) >= 0) {
|
||||
return(sbuf.isDir);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
gstat_t sbuf;
|
||||
|
||||
if (gstat(lpath, &sbuf) >= 0) {
|
||||
return(sbuf.st_mode & S_IFDIR);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Read a web page. Returns the number of _bytes_ read.
|
||||
* len is the size of buf, in bytes.
|
||||
*/
|
||||
|
||||
int websPageReadData(webs_t wp, char *buf, int nBytes)
|
||||
{
|
||||
|
||||
#ifdef WEBS_PAGE_ROM
|
||||
a_assert(websValid(wp));
|
||||
return websRomPageReadData(wp, buf, nBytes);
|
||||
#else
|
||||
a_assert(websValid(wp));
|
||||
return read(wp->docfd, buf, nBytes);
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Move file pointer offset bytes.
|
||||
*/
|
||||
|
||||
void websPageSeek(webs_t wp, long offset)
|
||||
{
|
||||
a_assert(websValid(wp));
|
||||
|
||||
#ifdef WEBS_PAGE_ROM
|
||||
websRomPageSeek(wp, offset, SEEK_CUR);
|
||||
#else
|
||||
lseek(wp->docfd, offset, SEEK_CUR);
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
* webrom.c -- Compiled Web Pages
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "wsIntrn.h"
|
||||
|
||||
websRomPageIndexType websRomPageIndex[] = {
|
||||
{ 0, 0, 0 },
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,233 +0,0 @@
|
||||
/*
|
||||
* webs.h -- GoAhead Web public header
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1992-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for information on usage and redistribution
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _h_WEBS
|
||||
#define _h_WEBS 1
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* GoAhead Web Server header. This defines the Web public APIs.
|
||||
* Include this header for files that contain ASP or Form procedures.
|
||||
* Include wsIntrn.h when creating URL handlers.
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#include "ej.h"
|
||||
#ifdef WEBS_SSL_SUPPORT
|
||||
#include "websSSL.h"
|
||||
#endif
|
||||
|
||||
/********************************** Defines ***********************************/
|
||||
/*
|
||||
* By license terms the server software name defined in the following line of
|
||||
* code must not be modified.
|
||||
*/
|
||||
#define WEBS_NAME T("GoAhead-Webs")
|
||||
#define WEBS_VERSION T("2.1.3")
|
||||
|
||||
#define WEBS_HEADER_BUFINC 512 /* Header buffer size */
|
||||
#define WEBS_ASP_BUFINC 512 /* Asp expansion increment */
|
||||
#define WEBS_MAX_PASS 32 /* Size of password */
|
||||
#define WEBS_BUFSIZE 1000 /* websWrite max output string */
|
||||
#define WEBS_MAX_HEADER (5 * 1024) /* Sanity check header */
|
||||
#define WEBS_MAX_URL 4096 /* Maximum URL size for sanity */
|
||||
#define WEBS_SOCKET_BUFSIZ 256 /* Bytes read from socket */
|
||||
|
||||
#define WEBS_HTTP_PORT T("httpPort")
|
||||
#define CGI_BIN T("cgi-bin")
|
||||
|
||||
/*
|
||||
* Request flags. Also returned by websGetRequestFlags().
|
||||
*/
|
||||
#define WEBS_LOCAL_PAGE 0x1 /* Request for local webs page */
|
||||
#define WEBS_KEEP_ALIVE 0x2 /* HTTP/1.1 keep alive */
|
||||
#define WEBS_DONT_USE_CACHE 0x4 /* Not implemented cache support */
|
||||
#define WEBS_COOKIE 0x8 /* Cookie supplied in request */
|
||||
#define WEBS_IF_MODIFIED 0x10 /* If-modified-since in request */
|
||||
#define WEBS_POST_REQUEST 0x20 /* Post request operation */
|
||||
#define WEBS_LOCAL_REQUEST 0x40 /* Request from this system */
|
||||
#define WEBS_HOME_PAGE 0x80 /* Request for the home page */
|
||||
#define WEBS_ASP 0x100 /* ASP request */
|
||||
#define WEBS_HEAD_REQUEST 0x200 /* Head request */
|
||||
#define WEBS_CLEN 0x400 /* Request had a content length */
|
||||
#define WEBS_FORM 0x800 /* Request is a form */
|
||||
#define WEBS_REQUEST_DONE 0x1000 /* Request complete */
|
||||
#define WEBS_POST_DATA 0x2000 /* Already appended post data */
|
||||
#define WEBS_CGI_REQUEST 0x4000 /* cgi-bin request */
|
||||
#define WEBS_SECURE 0x8000 /* connection uses SSL */
|
||||
#define WEBS_AUTH_BASIC 0x10000 /* Basic authentication request */
|
||||
#define WEBS_AUTH_DIGEST 0x20000 /* Digest authentication request */
|
||||
#define WEBS_HEADER_DONE 0x40000 /* Already output the HTTP header */
|
||||
|
||||
/*
|
||||
* URL handler flags
|
||||
*/
|
||||
#define WEBS_HANDLER_FIRST 0x1 /* Process this handler first */
|
||||
#define WEBS_HANDLER_LAST 0x2 /* Process this handler last */
|
||||
|
||||
/*
|
||||
* Per socket connection webs structure
|
||||
*/
|
||||
typedef struct websRec {
|
||||
ringq_t header; /* Header dynamic string */
|
||||
time_t since; /* Parsed if-modified-since time */
|
||||
sym_fd_t cgiVars; /* CGI standard variables */
|
||||
sym_fd_t cgiQuery; /* CGI decoded query string */
|
||||
time_t timestamp; /* Last transaction with browser */
|
||||
int timeout; /* Timeout handle */
|
||||
char_t ipaddr[32]; /* Connecting ipaddress */
|
||||
char_t type[64]; /* Mime type */
|
||||
char_t *dir; /* Directory containing the page */
|
||||
char_t *path; /* Path name without query */
|
||||
char_t *url; /* Full request url */
|
||||
char_t *host; /* Requested host */
|
||||
char_t *lpath; /* Cache local path name */
|
||||
char_t *query; /* Request query */
|
||||
char_t *decodedQuery; /* Decoded request query */
|
||||
char_t *authType; /* Authorization type (Basic/DAA) */
|
||||
char_t *password; /* Authorization password */
|
||||
char_t *userName; /* Authorization username */
|
||||
char_t *cookie; /* Cookie string */
|
||||
char_t *userAgent; /* User agent (browser) */
|
||||
char_t *protocol; /* Protocol (normally HTTP) */
|
||||
char_t *protoVersion; /* Protocol version */
|
||||
int sid; /* Socket id (handler) */
|
||||
int listenSid; /* Listen Socket id */
|
||||
int port; /* Request port number */
|
||||
int state; /* Current state */
|
||||
int flags; /* Current flags -- see above */
|
||||
int code; /* Request result code */
|
||||
int clen; /* Content length */
|
||||
int wid; /* Index into webs */
|
||||
char_t *cgiStdin; /* filename for CGI stdin */
|
||||
int docfd; /* Document file descriptor */
|
||||
int numbytes; /* Bytes to transfer to browser */
|
||||
int written; /* Bytes actually transferred */
|
||||
void (*writeSocket)(struct websRec *wp);
|
||||
#ifdef DIGEST_ACCESS_SUPPORT
|
||||
char_t *realm; /* usually the same as "host" from websRec */
|
||||
char_t *nonce; /* opaque-to-client string sent by server */
|
||||
char_t *digest; /* digest form of user password */
|
||||
char_t *uri; /* URI found in DAA header */
|
||||
char_t *opaque; /* opaque value passed from server */
|
||||
char_t *nc; /* nonce count */
|
||||
char_t *cnonce; /* check nonce */
|
||||
char_t *qop; /* quality operator */
|
||||
#endif
|
||||
#ifdef WEBS_SSL_SUPPORT
|
||||
websSSL_t *wsp; /* SSL data structure */
|
||||
#endif
|
||||
} websRec;
|
||||
|
||||
typedef websRec *webs_t;
|
||||
typedef websRec websType;
|
||||
|
||||
/******************************** Prototypes **********************************/
|
||||
extern int websAccept(int sid, char *ipaddr, int port, int listenSid);
|
||||
extern int websAspDefine(char_t *name,
|
||||
int (*fn)(int ejid, webs_t wp, int argc, char_t **argv));
|
||||
extern int websAspRequest(webs_t wp, char_t *lpath);
|
||||
extern void websCloseListen();
|
||||
extern int websDecode64(char_t *outbuf, char_t *string, int buflen);
|
||||
extern void websDecodeUrl(char_t *token, char_t *decoded, int len);
|
||||
extern void websDone(webs_t wp, int code);
|
||||
extern void websEncode64(char_t *outbuf, char_t *string, int buflen);
|
||||
extern void websError(webs_t wp, int code, char_t *msg, ...);
|
||||
/* function websErrorMsg() made extern 03 Jun 02 BgP */
|
||||
extern char_t *websErrorMsg(int code);
|
||||
extern void websFooter(webs_t wp);
|
||||
extern int websFormDefine(char_t *name, void (*fn)(webs_t wp,
|
||||
char_t *path, char_t *query));
|
||||
extern char_t *websGetDefaultDir();
|
||||
extern char_t *websGetDefaultPage();
|
||||
extern char_t *websGetHostUrl();
|
||||
extern char_t *websGetIpaddrUrl();
|
||||
extern char_t *websGetPassword();
|
||||
extern int websGetPort();
|
||||
extern char_t *websGetPublishDir(char_t *path, char_t **urlPrefix);
|
||||
extern char_t *websGetRealm();
|
||||
extern int websGetRequestBytes(webs_t wp);
|
||||
extern char_t *websGetRequestDir(webs_t wp);
|
||||
extern int websGetRequestFlags(webs_t wp);
|
||||
extern char_t *websGetRequestIpaddr(webs_t wp);
|
||||
extern char_t *websGetRequestLpath(webs_t wp);
|
||||
extern char_t *websGetRequestPath(webs_t wp);
|
||||
extern char_t *websGetRequestPassword(webs_t wp);
|
||||
extern char_t *websGetRequestType(webs_t wp);
|
||||
extern int websGetRequestWritten(webs_t wp);
|
||||
extern char_t *websGetVar(webs_t wp, char_t *var, char_t *def);
|
||||
extern int websCompareVar(webs_t wp, char_t *var, char_t *value);
|
||||
extern void websHeader(webs_t wp);
|
||||
extern int websOpenListen(int port, int retries);
|
||||
extern int websPageOpen(webs_t wp, char_t *lpath, char_t *path,
|
||||
int mode, int perm);
|
||||
extern void websPageClose(webs_t wp);
|
||||
extern int websPublish(char_t *urlPrefix, char_t *path);
|
||||
extern void websRedirect(webs_t wp, char_t *url);
|
||||
extern void websSecurityDelete();
|
||||
extern int websSecurityHandler(webs_t wp, char_t *urlPrefix,
|
||||
char_t *webDir, int arg, char_t *url, char_t *path,
|
||||
char_t *query);
|
||||
extern void websSetDefaultDir(char_t *dir);
|
||||
extern void websSetDefaultPage(char_t *page);
|
||||
extern void websSetEnv(webs_t wp);
|
||||
extern void websSetHost(char_t *host);
|
||||
extern void websSetIpaddr(char_t *ipaddr);
|
||||
extern void websSetPassword(char_t *password);
|
||||
extern void websSetRealm(char_t *realmName);
|
||||
extern void websSetRequestBytes(webs_t wp, int bytes);
|
||||
extern void websSetRequestFlags(webs_t wp, int flags);
|
||||
extern void websSetRequestLpath(webs_t wp, char_t *lpath);
|
||||
extern void websSetRequestPath(webs_t wp, char_t *dir, char_t *path);
|
||||
extern char_t *websGetRequestUserName(webs_t wp);
|
||||
extern void websSetRequestWritten(webs_t wp, int written);
|
||||
extern void websSetVar(webs_t wp, char_t *var, char_t *value);
|
||||
extern int websTestVar(webs_t wp, char_t *var);
|
||||
extern void websTimeoutCancel(webs_t wp);
|
||||
extern int websUrlHandlerDefine(char_t *urlPrefix, char_t *webDir,
|
||||
int arg, int (*fn)(webs_t wp, char_t *urlPrefix,
|
||||
char_t *webDir, int arg, char_t *url, char_t *path,
|
||||
char_t *query), int flags);
|
||||
extern int websUrlHandlerDelete(int (*fn)(webs_t wp, char_t *urlPrefix,
|
||||
char_t *webDir, int arg, char_t *url, char_t *path,
|
||||
char_t *query));
|
||||
extern int websUrlHandlerRequest(webs_t wp);
|
||||
extern int websUrlParse(char_t *url, char_t **buf, char_t **host,
|
||||
char_t **path, char_t **port, char_t **query,
|
||||
char_t **proto, char_t **tag, char_t **ext);
|
||||
extern char_t *websUrlType(char_t *webs, char_t *buf, int charCnt);
|
||||
extern int websWrite(webs_t wp, char_t* fmt, ...);
|
||||
extern int websWriteBlock(webs_t wp, char_t *buf, int nChars);
|
||||
extern int websWriteDataNonBlock(webs_t wp, char *buf, int nChars);
|
||||
extern int websValid(webs_t wp);
|
||||
extern int websValidateUrl(webs_t wp, char_t *path);
|
||||
extern void websSetTimeMark(webs_t wp);
|
||||
|
||||
/*
|
||||
* The following prototypes are used by the SSL patch found in websSSL.c
|
||||
*/
|
||||
extern int websAlloc(int sid);
|
||||
extern void websFree(webs_t wp);
|
||||
extern void websTimeout(void *arg, int id);
|
||||
extern void websReadEvent(webs_t wp);
|
||||
|
||||
/*
|
||||
* Prototypes for functions available when running as part of the
|
||||
* GoAhead Embedded Management Framework (EMF)
|
||||
*/
|
||||
#ifdef EMF
|
||||
extern void websFormExplain(webs_t wp, char_t *path, char_t *query);
|
||||
#endif
|
||||
|
||||
#endif /* _h_WEBS */
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,706 +0,0 @@
|
||||
/*
|
||||
* websSSL.c -- SSL envrionment creation
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* This module implements a patch into SSL implementations for the webs
|
||||
* module.
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#include "wsIntrn.h"
|
||||
#include "webs.h"
|
||||
#include "websSSL.h"
|
||||
|
||||
/******************************* Definitions **********************************/
|
||||
|
||||
#define DEFAULT_CERT_FILE "./server.pem"
|
||||
#define DEFAULT_KEY_FILE "./certs/cakey.pem"
|
||||
#define DEFAULT_CA_FILE "./certs/cacert.pem"
|
||||
#define DEFAULT_CA_PATH "./certs/"
|
||||
#define SSL_PORT 443
|
||||
|
||||
/*
|
||||
* Define the components of the apps_startup() macro
|
||||
*/
|
||||
|
||||
#ifdef SIGPIPE
|
||||
#define do_pipe_sig() signal(SIGPIPE,SIG_IGN)
|
||||
#else
|
||||
#define do_pipe_sig()
|
||||
#endif
|
||||
|
||||
#ifdef OPENSSL
|
||||
#define SSLC_add_all_algorithms() SSLeay_add_all_algorithms()
|
||||
#else
|
||||
extern void SSLC_add_all_algorithms(void);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define the apps_startup() macro
|
||||
*/
|
||||
|
||||
# if defined(MSDOS) || defined(WIN16) || defined(WIN32)
|
||||
# ifdef _O_BINARY
|
||||
# define apps_startup() \
|
||||
_fmode=_O_BINARY; do_pipe_sig(); CRYPTO_malloc_init(); \
|
||||
SSLC_add_all_algorithms()
|
||||
# else
|
||||
# define apps_startup() \
|
||||
_fmode=O_BINARY; do_pipe_sig(); CRYPTO_malloc_init(); \
|
||||
SSLC_add_all_algorithms()
|
||||
# endif
|
||||
# else
|
||||
# define apps_startup() do_pipe_sig(); SSLC_add_all_algorithms();
|
||||
# endif
|
||||
|
||||
/*************************** Forward Declarations *****************************/
|
||||
|
||||
static int websSSLSetCertStuff(SSL_CTX *ctx,
|
||||
char *cert_file,
|
||||
char *key_file);
|
||||
static int websSSLVerifyCallback(int ok, X509_STORE_CTX *ctx);
|
||||
static RSA *websSSLTempRSACallback(SSL *s, int is_export, int keylength);
|
||||
|
||||
static int websSSLReadEvent (webs_t wp);
|
||||
static int websSSLAccept(int sid, char *ipaddr, int port, int listenSid);
|
||||
static void websSSLSocketEvent(int sid, int mask, int data);
|
||||
|
||||
/*********************************** Locals ***********************************/
|
||||
|
||||
static int sslListenSock = -1; /* Listen socket */
|
||||
static SSL_CTX *sslctx = NULL;
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Start up the SSL Context for the application, and start a listen on the
|
||||
* SSL port (usually 443, and defined by SSL_PORT)
|
||||
* Return 0 on success, -1 on failure.
|
||||
*/
|
||||
|
||||
int websSSLOpen()
|
||||
{
|
||||
char *certFile, *keyFile, *CApath, *CAfile;
|
||||
SSL_METHOD *meth;
|
||||
|
||||
/*
|
||||
* Install and initialize the SSL library
|
||||
*/
|
||||
apps_startup();
|
||||
trace(7, T("SSL: Initializing SSL\n"));
|
||||
|
||||
#ifdef SSLC
|
||||
SSL_library_init();
|
||||
#endif
|
||||
|
||||
SSL_load_error_strings();
|
||||
|
||||
#ifdef OPENSSL
|
||||
SSLeay_add_ssl_algorithms();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Important! Enable both SSL versions 2 and 3
|
||||
*/
|
||||
meth = SSLv23_server_method();
|
||||
sslctx = SSL_CTX_new(meth);
|
||||
|
||||
a_assert(sslctx);
|
||||
|
||||
if (sslctx == NULL) {
|
||||
trace(2, T("SSL: Unable to create SSL context!\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust some SSL Context variables
|
||||
*/
|
||||
SSL_CTX_set_quiet_shutdown(sslctx, 1);
|
||||
SSL_CTX_set_options(sslctx, 0);
|
||||
SSL_CTX_sess_set_cache_size(sslctx, 128);
|
||||
|
||||
/*
|
||||
* Set the certificate verification locations
|
||||
*/
|
||||
CApath = DEFAULT_CA_PATH;
|
||||
CAfile = DEFAULT_CA_FILE;
|
||||
if ((!SSL_CTX_load_verify_locations(sslctx, CAfile, CApath)) ||
|
||||
(!SSL_CTX_set_default_verify_paths(sslctx))) {
|
||||
trace(2, T("SSL: Unable to set cert verification locations!\n"));
|
||||
websSSLClose();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the certificate and key files for the SSL context
|
||||
*/
|
||||
certFile = DEFAULT_CERT_FILE;
|
||||
keyFile = NULL;
|
||||
if (websSSLSetCertStuff(sslctx, certFile, keyFile) != 0) {
|
||||
websSSLClose();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the RSA callback for the SSL context
|
||||
*/
|
||||
SSL_CTX_set_tmp_rsa_callback(sslctx, websSSLTempRSACallback);
|
||||
|
||||
/*
|
||||
* Set the verification callback for the SSL context
|
||||
*/
|
||||
SSL_CTX_set_verify(sslctx, SSL_VERIFY_NONE, websSSLVerifyCallback);
|
||||
|
||||
/*
|
||||
* Set the certificate authority list for the client
|
||||
*/
|
||||
SSL_CTX_set_client_CA_list(sslctx, SSL_load_client_CA_file(CAfile));
|
||||
|
||||
/*
|
||||
* Open the socket
|
||||
*/
|
||||
sslListenSock = socketOpenConnection(NULL, SSL_PORT,
|
||||
websSSLAccept, SOCKET_BLOCK);
|
||||
|
||||
if (sslListenSock < 0) {
|
||||
trace(2, T("SSL: Unable to open SSL socket on port <%d>!\n"),
|
||||
SSL_PORT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Return TRUE if websSSL has been opened
|
||||
*/
|
||||
|
||||
int websSSLIsOpen()
|
||||
{
|
||||
return (sslListenSock != -1);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Stops the SSL
|
||||
*/
|
||||
|
||||
void websSSLClose()
|
||||
{
|
||||
trace(7, T("SSL: Closing SSL\n"));
|
||||
|
||||
if (sslctx != NULL) {
|
||||
SSL_CTX_free(sslctx);
|
||||
sslctx = NULL;
|
||||
}
|
||||
|
||||
if (sslListenSock != -1) {
|
||||
socketCloseConnection(sslListenSock);
|
||||
sslListenSock = -1;
|
||||
}
|
||||
|
||||
#ifdef SSLC
|
||||
SSL_library_cleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Accept a connection
|
||||
*/
|
||||
|
||||
int websSSLAccept(int sid, char *ipaddr, int port, int listenSid)
|
||||
{
|
||||
webs_t wp;
|
||||
int wid;
|
||||
|
||||
a_assert(ipaddr && *ipaddr);
|
||||
a_assert(sid >= 0);
|
||||
a_assert(port >= 0);
|
||||
|
||||
/*
|
||||
* Allocate a new handle for this accepted connection. This will allocate
|
||||
* a webs_t structure in the webs[] list
|
||||
*/
|
||||
if ((wid = websAlloc(sid)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
wp = webs[wid];
|
||||
a_assert(wp);
|
||||
wp->listenSid = listenSid;
|
||||
|
||||
ascToUni(wp->ipaddr, ipaddr, min(sizeof(wp->ipaddr), strlen(ipaddr)+1));
|
||||
|
||||
/*
|
||||
* Check if this is a request from a browser on this system. This is useful
|
||||
* to know for permitting administrative operations only for local access
|
||||
*/
|
||||
if (gstrcmp(wp->ipaddr, T("127.0.0.1")) == 0 ||
|
||||
gstrcmp(wp->ipaddr, websIpaddr) == 0 ||
|
||||
gstrcmp(wp->ipaddr, websHost) == 0) {
|
||||
wp->flags |= WEBS_LOCAL_REQUEST;
|
||||
}
|
||||
/*
|
||||
* Since the acceptance came in on this channel, it must be secure
|
||||
*/
|
||||
wp->flags |= WEBS_SECURE;
|
||||
|
||||
/*
|
||||
* Arrange for websSocketEvent to be called when read data is available
|
||||
*/
|
||||
socketCreateHandler(sid, SOCKET_READABLE, websSSLSocketEvent, (int) wp);
|
||||
|
||||
/*
|
||||
* Arrange for a timeout to kill hung requests
|
||||
*/
|
||||
wp->timeout = emfSchedCallback(WEBS_TIMEOUT, websTimeout, (void *) wp);
|
||||
trace(8, T("webs: accept request\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* The webs socket handler. Called in response to I/O. We just pass control
|
||||
* to the relevant read or write handler. A pointer to the webs structure
|
||||
* is passed as an (int) in iwp.
|
||||
*/
|
||||
|
||||
static void websSSLSocketEvent(int sid, int mask, int iwp)
|
||||
{
|
||||
webs_t wp;
|
||||
|
||||
wp = (webs_t) iwp;
|
||||
a_assert(wp);
|
||||
|
||||
if (! websValid(wp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mask & SOCKET_READABLE) {
|
||||
websSSLReadEvent(wp);
|
||||
}
|
||||
if (mask & SOCKET_WRITABLE) {
|
||||
if (wp->writeSocket) {
|
||||
(*wp->writeSocket)(wp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Handler for SSL Read Events
|
||||
*/
|
||||
|
||||
static int websSSLReadEvent (webs_t wp)
|
||||
{
|
||||
int ret, sock;
|
||||
socket_t *sptr;
|
||||
SSL *ssl;
|
||||
BIO *bio, *bioSSL, *bioSock;
|
||||
#ifdef DEV
|
||||
const char *ciphers;
|
||||
#endif
|
||||
|
||||
a_assert (wp);
|
||||
a_assert(websValid(wp));
|
||||
|
||||
sptr = socketPtr(wp->sid);
|
||||
a_assert(sptr);
|
||||
|
||||
sock = sptr->sock;
|
||||
|
||||
/*
|
||||
* Create a new BIO and SSL session for this web request
|
||||
*/
|
||||
bio = BIO_new(BIO_f_buffer());
|
||||
a_assert(bio);
|
||||
|
||||
if (!BIO_set_write_buffer_size(bio, 128)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssl = (SSL *) SSL_new(sslctx);
|
||||
a_assert(ssl);
|
||||
|
||||
if (ssl == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_set_session(ssl, NULL);
|
||||
|
||||
bioSSL = BIO_new(BIO_f_ssl());
|
||||
a_assert(bioSSL);
|
||||
|
||||
bioSock = BIO_new_socket(sock, BIO_NOCLOSE);
|
||||
a_assert(bioSock);
|
||||
|
||||
SSL_set_bio(ssl, bioSock, bioSock);
|
||||
SSL_set_accept_state(ssl);
|
||||
|
||||
ret = BIO_set_ssl(bioSSL, ssl, BIO_CLOSE);
|
||||
BIO_push(bio, bioSSL);
|
||||
|
||||
#ifdef DEV
|
||||
ciphers = SSL_get_cipher_list(ssl, 10);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Create the SSL data structure in the wp.
|
||||
*/
|
||||
#ifdef WEBS_SSL_SUPPORT
|
||||
wp->wsp = balloc(B_L, sizeof(websSSL_t));
|
||||
a_assert (wp->wsp);
|
||||
(wp->wsp)->bio = bio;
|
||||
(wp->wsp)->ssl = ssl;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Call the default Read Event
|
||||
*/
|
||||
websReadEvent(wp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* SSL Verification Callback
|
||||
*/
|
||||
|
||||
static int sslVerifyDepth = 0;
|
||||
static int sslVerifyError = X509_V_OK;
|
||||
|
||||
int websSSLVerifyCallback(int ok, X509_STORE_CTX *ctx)
|
||||
{
|
||||
char buf[256];
|
||||
X509 *errCert;
|
||||
int err;
|
||||
int depth;
|
||||
|
||||
errCert = X509_STORE_CTX_get_current_cert(ctx);
|
||||
err = X509_STORE_CTX_get_error(ctx);
|
||||
depth = X509_STORE_CTX_get_error_depth(ctx);
|
||||
|
||||
X509_NAME_oneline(X509_get_subject_name(errCert), buf, 256);
|
||||
|
||||
if (!ok) {
|
||||
if (sslVerifyDepth >= depth) {
|
||||
ok = 1;
|
||||
sslVerifyError = X509_V_OK;
|
||||
} else {
|
||||
ok=0;
|
||||
sslVerifyError = X509_V_ERR_CERT_CHAIN_TOO_LONG;
|
||||
}
|
||||
}
|
||||
|
||||
switch (err) {
|
||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
|
||||
#ifdef OPENSSL
|
||||
X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case X509_V_ERR_CERT_NOT_YET_VALID:
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
|
||||
case X509_V_ERR_CERT_HAS_EXPIRED:
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
|
||||
break;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Set the SSL certificate and key for the SSL context
|
||||
*/
|
||||
|
||||
int websSSLSetCertStuff(SSL_CTX *ctx, char *certFile, char *keyFile)
|
||||
{
|
||||
a_assert (ctx);
|
||||
a_assert (certFile);
|
||||
|
||||
if (certFile != NULL) {
|
||||
if (SSL_CTX_use_certificate_file(ctx, certFile,
|
||||
SSL_FILETYPE_PEM) <= 0) {
|
||||
trace(2, T("SSL: Unable to set certificate file <%s>\n"),
|
||||
certFile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (keyFile == NULL) {
|
||||
keyFile = certFile;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_PrivateKey_file(ctx, keyFile, SSL_FILETYPE_PEM) <= 0) {
|
||||
trace(2, T("SSL: Unable to set private key file <%s>\n"),
|
||||
keyFile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we know that a key and cert have been set against
|
||||
* the SSL context
|
||||
*/
|
||||
if (!SSL_CTX_check_private_key(ctx)) {
|
||||
trace(2, T("SSL: Check of private key file <%s> FAILED!\n"),
|
||||
keyFile);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Set certificate file for SSL context
|
||||
*/
|
||||
|
||||
int websSSLSetCertFile(char_t *certFile)
|
||||
{
|
||||
a_assert (sslctx);
|
||||
a_assert (certFile);
|
||||
|
||||
if (sslctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_certificate_file(sslctx, certFile,
|
||||
SSL_FILETYPE_PEM) <= 0) {
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* Confirm that the certificate and the private key jive.
|
||||
*/
|
||||
if (!SSL_CTX_check_private_key(sslctx)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Set key file for SSL context
|
||||
*/
|
||||
|
||||
int websSSLSetKeyFile(char_t *keyFile)
|
||||
{
|
||||
a_assert (sslctx);
|
||||
a_assert (keyFile);
|
||||
|
||||
if (sslctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_PrivateKey_file(sslctx, keyFile, SSL_FILETYPE_PEM) <= 0) {
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* Confirm that the certificate and the private key jive.
|
||||
*/
|
||||
if (!SSL_CTX_check_private_key(sslctx)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SSLC
|
||||
extern RSA *RSA_new(void);
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* the Temporary RSA callback
|
||||
*/
|
||||
|
||||
static RSA *websSSLTempRSACallback(SSL *ssl, int isExport, int keyLength)
|
||||
{
|
||||
static RSA *rsaTemp = NULL;
|
||||
|
||||
if (rsaTemp == NULL) {
|
||||
|
||||
#ifdef OPENSSL
|
||||
rsaTemp = RSA_generate_key(keyLength, RSA_F4, NULL, NULL);
|
||||
#endif
|
||||
|
||||
#ifdef SSLC
|
||||
rsaTemp = RSA_new();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
return rsaTemp;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Free SSL resources
|
||||
*/
|
||||
|
||||
int websSSLFree(websSSL_t *wsp)
|
||||
{
|
||||
if (wsp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure we re-use sessions
|
||||
*/
|
||||
if (wsp->ssl != NULL) {
|
||||
SSL_set_shutdown(wsp->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
|
||||
}
|
||||
|
||||
if (wsp->bio != NULL) {
|
||||
BIO_free_all(wsp->bio);
|
||||
}
|
||||
|
||||
bfree(B_L, wsp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Return Eof for the SSL BIO
|
||||
*/
|
||||
|
||||
int websSSLEof(websSSL_t *wsp)
|
||||
{
|
||||
a_assert(wsp);
|
||||
|
||||
if ((wsp == NULL) || (wsp->bio == NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return BIO_eof(wsp->bio);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Perform a read of the SSL BIO
|
||||
*/
|
||||
|
||||
int websSSLRead(websSSL_t *wsp, char_t *buf, int len)
|
||||
{
|
||||
a_assert(wsp);
|
||||
a_assert(buf);
|
||||
|
||||
if ((wsp == NULL) || (wsp->bio == NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return BIO_read(wsp->bio, buf, len);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Perform a gets of the SSL BIO, returning an balloc'ed string
|
||||
*/
|
||||
|
||||
#define BUF_BLOCK 256
|
||||
|
||||
int websSSLGets(websSSL_t *wsp, char_t **buf)
|
||||
{
|
||||
int rc, len, lenBuf;
|
||||
char c;
|
||||
|
||||
a_assert(wsp);
|
||||
a_assert(buf);
|
||||
|
||||
lenBuf = 0;
|
||||
len = 0;
|
||||
|
||||
if ((wsp == NULL) || (wsp->bio == NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
|
||||
if ((rc = BIO_read(wsp->bio, &c, 1)) < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
/*
|
||||
* If there is a partial line and we are at EOF, pretend we saw a '\n'
|
||||
*/
|
||||
if (len > 0 && BIO_eof(wsp->bio)) {
|
||||
c = '\n';
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If a newline is seen, return the data excluding the new line to the
|
||||
* caller. If carriage return is seen, just eat it.
|
||||
*/
|
||||
if (c == '\n') {
|
||||
if ((len > 0) && (len < lenBuf)) {
|
||||
(*buf)[len] = 0;
|
||||
}
|
||||
return len;
|
||||
} else if (c == '\r') {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Append character to buf
|
||||
*/
|
||||
if (len >= lenBuf) {
|
||||
lenBuf += BUF_BLOCK;
|
||||
*buf = brealloc(B_L, *buf, lenBuf);
|
||||
}
|
||||
|
||||
a_assert(*buf);
|
||||
(*buf)[len] = c;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Perform a write to the SSL BIO
|
||||
*/
|
||||
|
||||
int websSSLWrite(websSSL_t *wsp, char_t *buf, int len)
|
||||
{
|
||||
a_assert(wsp);
|
||||
a_assert(buf);
|
||||
|
||||
if ((wsp == NULL) || (wsp->bio == NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return BIO_write(wsp->bio, buf, len);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Perform a flush of the SSL BIO
|
||||
*/
|
||||
|
||||
int websSSLFlush(websSSL_t *wsp)
|
||||
{
|
||||
a_assert(wsp);
|
||||
|
||||
if ((wsp == NULL) || (wsp->bio == NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return BIO_flush(wsp->bio);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* websSSL.h -- SSL Patch header
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1992-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for information on usage and redistribution
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _h_websSSL
|
||||
#define _h_websSSL 1
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* Header file for the GoAhead Patch for SSL. This defines the interface to
|
||||
* integrate SSL into the GoAhead Webserver.
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
|
||||
#ifdef OPENSSL
|
||||
#define SSLEAY /* turn off a few special case MONOLITH macros */
|
||||
#define USE_SOCKETS /* needed for the _O_BINARY defs in the MS world */
|
||||
#include <openssl/ssl.h>
|
||||
#else
|
||||
#include <sslc.h>
|
||||
#endif
|
||||
|
||||
#ifndef UEMF
|
||||
#include "basic/basic.h"
|
||||
#include "emf/emf.h"
|
||||
#else
|
||||
#include "uemf.h"
|
||||
#endif
|
||||
|
||||
/********************************** Defines ***********************************/
|
||||
|
||||
typedef struct {
|
||||
SSL *ssl;
|
||||
BIO *bio;
|
||||
} websSSL_t;
|
||||
|
||||
|
||||
/******************************** Prototypes **********************************/
|
||||
|
||||
extern int websSSLOpen();
|
||||
extern int websSSLIsOpen();
|
||||
extern void websSSLClose();
|
||||
|
||||
extern int websSSLWrite(websSSL_t *wsp, char_t *buf, int nChars);
|
||||
extern int websSSLGets(websSSL_t *wsp, char_t **buf);
|
||||
extern int websSSLRead(websSSL_t *wsp, char_t *buf, int nChars);
|
||||
extern int websSSLEof(websSSL_t *wsp);
|
||||
|
||||
extern int websSSLFree(websSSL_t *wsp);
|
||||
extern int websSSLFlush(websSSL_t *wsp);
|
||||
|
||||
extern int websSSLSetKeyFile(char_t *keyFile);
|
||||
extern int websSSLSetCertFile(char_t *certFile);
|
||||
|
||||
|
||||
#endif /* _h_websSSL */
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -1,244 +0,0 @@
|
||||
/*
|
||||
* websda.c -- Digest Access Authentication routines
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* Routines for generating DAA data. The module uses the
|
||||
* "RSA Data Security, Inc. MD5 Message-Digest Algorithm" found in md5c.c
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#ifndef CE
|
||||
#include <time.h>
|
||||
#endif
|
||||
#include "websda.h"
|
||||
#include "md5.h"
|
||||
|
||||
/******************************** Local Data **********************************/
|
||||
|
||||
#define RANDOMKEY T("onceuponatimeinparadise")
|
||||
#define NONCE_SIZE 34
|
||||
#define HASH_SIZE 16
|
||||
|
||||
/*********************************** Code *************************************/
|
||||
/*
|
||||
* websMD5binary returns the MD5 hash
|
||||
*/
|
||||
|
||||
char *websMD5binary(unsigned char *buf, int length)
|
||||
{
|
||||
const char *hex = "0123456789abcdef";
|
||||
MD5_CONTEXT md5ctx;
|
||||
unsigned char hash[HASH_SIZE];
|
||||
char *r, *strReturn;
|
||||
char result[(HASH_SIZE * 2) + 1];
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Take the MD5 hash of the string argument.
|
||||
*/
|
||||
MD5Init(&md5ctx);
|
||||
MD5Update(&md5ctx, buf, (unsigned int)length);
|
||||
MD5Final(hash, &md5ctx);
|
||||
|
||||
/*
|
||||
* Prepare the resulting hash string
|
||||
*/
|
||||
for (i = 0, r = result; i < 16; i++) {
|
||||
*r++ = hex[hash[i] >> 4];
|
||||
*r++ = hex[hash[i] & 0xF];
|
||||
}
|
||||
|
||||
/*
|
||||
* Zero terminate the hash string
|
||||
*/
|
||||
*r = '\0';
|
||||
|
||||
/*
|
||||
* Allocate a new copy of the hash string
|
||||
*/
|
||||
strReturn = balloc(B_L, sizeof(result));
|
||||
strcpy(strReturn, result);
|
||||
|
||||
return strReturn;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* Convenience call to websMD5binary
|
||||
* (Performs char_t to char conversion and back)
|
||||
*/
|
||||
|
||||
char_t *websMD5(char_t *string)
|
||||
{
|
||||
char_t *strReturn;
|
||||
|
||||
a_assert(string && *string);
|
||||
|
||||
if (string && *string) {
|
||||
char *strTemp, *strHash;
|
||||
int nLen;
|
||||
/*
|
||||
* Convert input char_t string to char string
|
||||
*/
|
||||
nLen = gstrlen(string);
|
||||
strTemp = ballocUniToAsc(string, nLen + 1);
|
||||
/*
|
||||
* Execute the digest calculation
|
||||
*/
|
||||
strHash = websMD5binary((unsigned char *)strTemp, nLen);
|
||||
/*
|
||||
* Convert the returned char string digest to a char_t string
|
||||
*/
|
||||
nLen = strlen(strHash);
|
||||
strReturn = ballocAscToUni(strHash, nLen);
|
||||
/*
|
||||
* Free up the temporary allocated resources
|
||||
*/
|
||||
bfree(B_L, strTemp);
|
||||
bfree(B_L, strHash);
|
||||
} else {
|
||||
strReturn = NULL;
|
||||
}
|
||||
|
||||
return strReturn;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Get a Nonce value for passing along to the client. This function
|
||||
* composes the string "RANDOMKEY:timestamp:myrealm" and
|
||||
* calculates the MD5 digest placing it in output.
|
||||
*/
|
||||
|
||||
char_t *websCalcNonce(webs_t wp)
|
||||
{
|
||||
char_t *nonce, *prenonce;
|
||||
struct tm *newtime;
|
||||
time_t longTime;
|
||||
|
||||
a_assert(wp);
|
||||
/*
|
||||
* Get time as long integer.
|
||||
*/
|
||||
time(&longTime);
|
||||
/*
|
||||
* Convert to local time.
|
||||
*/
|
||||
newtime = localtime(&longTime);
|
||||
/*
|
||||
* Create prenonce string.
|
||||
*/
|
||||
prenonce = NULL;
|
||||
#ifdef DIGEST_ACCESS_SUPPORT
|
||||
fmtAlloc(&prenonce, 256, T("%s:%s:%s"), RANDOMKEY, gasctime(newtime),
|
||||
wp->realm);
|
||||
#else
|
||||
fmtAlloc(&prenonce, 256, T("%s:%s:%s"), RANDOMKEY, gasctime(newtime),
|
||||
RANDOMKEY);
|
||||
#endif
|
||||
a_assert(prenonce);
|
||||
/*
|
||||
* Create the nonce
|
||||
*/
|
||||
nonce = websMD5(prenonce);
|
||||
/*
|
||||
* Cleanup
|
||||
*/
|
||||
bfreeSafe(B_L, prenonce);
|
||||
|
||||
return nonce;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Get an Opaque value for passing along to the client
|
||||
*/
|
||||
|
||||
char_t *websCalcOpaque(webs_t wp)
|
||||
{
|
||||
char_t *opaque;
|
||||
a_assert(wp);
|
||||
/*
|
||||
* Temporary stub!
|
||||
*/
|
||||
opaque = bstrdup(B_L, T("5ccc069c403ebaf9f0171e9517f40e41"));
|
||||
|
||||
return opaque;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Get a Digest value using the MD5 algorithm
|
||||
*/
|
||||
|
||||
char_t *websCalcDigest(webs_t wp)
|
||||
{
|
||||
#ifdef DIGEST_ACCESS_SUPPORT
|
||||
char_t *digest, *a1, *a1prime, *a2, *a2prime, *preDigest, *method;
|
||||
|
||||
a_assert(wp);
|
||||
digest = NULL;
|
||||
|
||||
/*
|
||||
* Calculate first portion of digest H(A1)
|
||||
*/
|
||||
a1 = NULL;
|
||||
fmtAlloc(&a1, 255, T("%s:%s:%s"), wp->userName, wp->realm, wp->password);
|
||||
a_assert(a1);
|
||||
a1prime = websMD5(a1);
|
||||
bfreeSafe(B_L, a1);
|
||||
/*
|
||||
* Calculate second portion of digest H(A2)
|
||||
*/
|
||||
method = websGetVar(wp, T("REQUEST_METHOD"), NULL);
|
||||
a_assert(method);
|
||||
a2 = NULL;
|
||||
fmtAlloc(&a2, 255, T("%s:%s"), method, wp->uri);
|
||||
a_assert(a2);
|
||||
a2prime = websMD5(a2);
|
||||
bfreeSafe(B_L, a2);
|
||||
/*
|
||||
* Construct final digest KD(H(A1):nonce:H(A2))
|
||||
*/
|
||||
a_assert(a1prime);
|
||||
a_assert(a2prime);
|
||||
a_assert(wp->nonce);
|
||||
|
||||
preDigest = NULL;
|
||||
if (!wp->qop) {
|
||||
fmtAlloc(&preDigest, 255, T("%s:%s:%s"), a1prime, wp->nonce, a2prime);
|
||||
} else {
|
||||
fmtAlloc(&preDigest, 255, T("%s:%s:%s:%s:%s:%s"),
|
||||
a1prime,
|
||||
wp->nonce,
|
||||
wp->nc,
|
||||
wp->cnonce,
|
||||
wp->qop,
|
||||
a2prime);
|
||||
}
|
||||
|
||||
a_assert(preDigest);
|
||||
digest = websMD5(preDigest);
|
||||
/*
|
||||
* Now clean up
|
||||
*/
|
||||
bfreeSafe(B_L, a1prime);
|
||||
bfreeSafe(B_L, a2prime);
|
||||
bfreeSafe(B_L, preDigest);
|
||||
return digest;
|
||||
#else
|
||||
return NULL;
|
||||
#endif /* DIGEST_ACCESS_SUPPORT */
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* websda.h -- GoAhead Digest Access Authentication public header
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1992-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for information on usage and redistribution
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _h_WEBSDA
|
||||
#define _h_WEBSDA 1
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* GoAhead Digest Access Authentication header. This defines the Digest
|
||||
* access authentication public APIs. Include this header for files that
|
||||
* use DAA functions
|
||||
*/
|
||||
|
||||
/********************************* Includes ***********************************/
|
||||
|
||||
#ifndef UEMF
|
||||
#include "basic/basic.h"
|
||||
#include "emf/emf.h"
|
||||
#else
|
||||
#include "uemf.h"
|
||||
#endif
|
||||
|
||||
#include "webs.h"
|
||||
|
||||
/****************************** Definitions ***********************************/
|
||||
|
||||
extern char_t *websCalcNonce(webs_t wp);
|
||||
extern char_t *websCalcOpaque(webs_t wp);
|
||||
extern char_t *websCalcDigest(webs_t wp);
|
||||
|
||||
#endif /* _h_WEBSDA */
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,217 +0,0 @@
|
||||
/*
|
||||
* websuemf.c -- GoAhead Micro Embedded Management Framework
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for usage and redistribution license requirements
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/********************************** Description *******************************/
|
||||
|
||||
/*
|
||||
* This modules provides compatibility with the full GoAhead EMF.
|
||||
*/
|
||||
|
||||
/*********************************** Includes *********************************/
|
||||
|
||||
#include "ejIntrn.h"
|
||||
#include "wsIntrn.h"
|
||||
|
||||
/*********************************** Defines **********************************/
|
||||
|
||||
/*
|
||||
* This structure stores scheduled events.
|
||||
*/
|
||||
typedef struct {
|
||||
void (*routine)(void *arg, int id);
|
||||
void *arg;
|
||||
time_t at;
|
||||
int schedid;
|
||||
} sched_t;
|
||||
|
||||
/*********************************** Locals ***********************************/
|
||||
|
||||
static sched_t **sched;
|
||||
static int schedMax;
|
||||
|
||||
/************************************* Code ***********************************/
|
||||
/*
|
||||
* Evaluate a script
|
||||
*/
|
||||
|
||||
int scriptEval(int engine, char_t *cmd, char_t **result, int chan)
|
||||
{
|
||||
int ejid;
|
||||
|
||||
if (engine == EMF_SCRIPT_EJSCRIPT) {
|
||||
ejid = (int) chan;
|
||||
/*
|
||||
* NOTE -- to disable better reporting of ASP errors, change the
|
||||
* following line of code to
|
||||
* if (ejEval(ejid, cmd, NULL) ) {
|
||||
*/
|
||||
if (ejEval(ejid, cmd, result) ) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Compare strings, ignoring case: normal strcmp return codes.
|
||||
*
|
||||
* WARNING: It is not good form to increment or decrement pointers inside a
|
||||
* "call" to tolower et al. These can be MACROS, and have undesired side
|
||||
* effects.
|
||||
*/
|
||||
|
||||
int strcmpci(char_t *s1, char_t *s2)
|
||||
{
|
||||
int rc;
|
||||
|
||||
a_assert(s1 && s2);
|
||||
if (s1 == NULL || s2 == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (s1 == s2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
rc = gtolower(*s1) - gtolower(*s2);
|
||||
if (*s1 == '\0') {
|
||||
break;
|
||||
}
|
||||
s1++;
|
||||
s2++;
|
||||
} while (rc == 0);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* This function is called when a scheduled process time has come.
|
||||
*/
|
||||
|
||||
void TimerProc(int schedid)
|
||||
{
|
||||
sched_t *s;
|
||||
|
||||
a_assert(0 <= schedid && schedid < schedMax);
|
||||
s = sched[schedid];
|
||||
a_assert(s);
|
||||
|
||||
(s->routine)(s->arg, s->schedid);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Schedule an event in delay milliseconds time. We will use 1 second
|
||||
* granularity for webServer.
|
||||
*/
|
||||
|
||||
int emfSchedCallback(int delay, emfSchedProc *proc, void *arg)
|
||||
{
|
||||
sched_t *s;
|
||||
int schedid;
|
||||
|
||||
if ((schedid = hAllocEntry((void*) &sched, &schedMax,
|
||||
sizeof(sched_t))) < 0) {
|
||||
return -1;
|
||||
}
|
||||
s = sched[schedid];
|
||||
s->routine = proc;
|
||||
s->arg = arg;
|
||||
s->schedid = schedid;
|
||||
|
||||
/*
|
||||
* Round the delay up to seconds.
|
||||
*/
|
||||
s->at = ((delay + 500) / 1000) + time(0);
|
||||
|
||||
return schedid;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Reschedule to a new delay.
|
||||
*/
|
||||
|
||||
void emfReschedCallback(int schedid, int delay)
|
||||
{
|
||||
sched_t *s;
|
||||
|
||||
if (sched == NULL || schedid == -1 || schedid >= schedMax ||
|
||||
(s = sched[schedid]) == NULL) {
|
||||
return;
|
||||
}
|
||||
s->at = ((delay + 500) / 1000) + time(0);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void emfUnschedCallback(int schedid)
|
||||
{
|
||||
sched_t *s;
|
||||
|
||||
if (sched == NULL || schedid == -1 || schedid >= schedMax ||
|
||||
(s = sched[schedid]) == NULL) {
|
||||
return;
|
||||
}
|
||||
bfree(B_L, s);
|
||||
schedMax = hFree((void*) &sched, schedid);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Take the tasks off the queue in a round robin fashion.
|
||||
*/
|
||||
|
||||
void emfSchedProcess()
|
||||
{
|
||||
sched_t *s;
|
||||
int schedid;
|
||||
static int next = 0;
|
||||
|
||||
/*
|
||||
* If schedMax is 0, there are no tasks scheduled, so just return.
|
||||
*/
|
||||
if (schedMax <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If next >= schedMax, the schedule queue was reduced in our absence
|
||||
* so reset next to 0 to start from the begining of the queue again.
|
||||
*/
|
||||
if (next >= schedMax) {
|
||||
next = 0;
|
||||
}
|
||||
|
||||
schedid = next;
|
||||
for (;;) {
|
||||
if ((s = sched[schedid]) != NULL && (int)s->at <= (int)time(0)) {
|
||||
TimerProc(schedid);
|
||||
next = schedid + 1;
|
||||
return;
|
||||
}
|
||||
if (++schedid >= schedMax) {
|
||||
schedid = 0;
|
||||
}
|
||||
if (schedid == next) {
|
||||
/*
|
||||
* We've gone all the way through the queue without finding
|
||||
* anything to do so just return.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1,309 +0,0 @@
|
||||
/*
|
||||
* wsIntrn.h -- Internal GoAhead Web server header
|
||||
*
|
||||
* Copyright (c) GoAhead Software Inc., 1992-2000. All Rights Reserved.
|
||||
*
|
||||
* See the file "license.txt" for information on usage and redistribution
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _h_WEBS_INTERNAL
|
||||
#define _h_WEBS_INTERNAL 1
|
||||
|
||||
/******************************** Description *********************************/
|
||||
|
||||
/*
|
||||
* Internal GoAhead Web Server header. This defines the Web private APIs
|
||||
* Include this header when you want to create URL handlers.
|
||||
*/
|
||||
|
||||
/*********************************** Defines **********************************/
|
||||
|
||||
/*
|
||||
* Define this to enable logging of web accesses to a file
|
||||
* #define WEBS_LOG_SUPPORT 1
|
||||
*
|
||||
* Define this to enable HTTP/1.1 keep alive support
|
||||
* #define WEBS_KEEP_ALIVE_SUPPORT 1
|
||||
*
|
||||
* Define this to enable if-modified-since support
|
||||
* #define WEBS_IF_MODIFIED_SUPPORT 1
|
||||
*
|
||||
* Define this to support proxy capability and track local vs remote request
|
||||
* Note: this is not yet fully implemented.
|
||||
* #define WEBS_PROXY_SUPPORT 1
|
||||
*
|
||||
* Define this to support reading pages from ROM
|
||||
* #define WEBS_PAGE_ROM 1
|
||||
*
|
||||
* Define this to enable memory allocation and stack usage tracking
|
||||
* #define B_STATS 1
|
||||
*/
|
||||
|
||||
/********************************** Includes **********************************/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef NETWARE
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#ifdef CE
|
||||
#ifndef UEMF
|
||||
#include <io.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NW
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifdef SCOV5
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef LYNX
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef UNIX
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef QNX4
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <unix.h>
|
||||
#endif
|
||||
|
||||
#ifdef UW
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifdef VXWORKS
|
||||
#include <vxWorks.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifdef SOLARIS
|
||||
#include <macros.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifdef UEMF
|
||||
#include "uemf.h"
|
||||
#include "ejIntrn.h"
|
||||
#else
|
||||
#include "emf/emfInternal.h"
|
||||
#include "ej/ejIntrn.h"
|
||||
#endif
|
||||
|
||||
#include "webs.h"
|
||||
|
||||
/********************************** Defines ***********************************/
|
||||
/*
|
||||
* Read handler flags and state
|
||||
*/
|
||||
#define WEBS_BEGIN 0x1 /* Beginning state */
|
||||
#define WEBS_HEADER 0x2 /* Ready to read first line */
|
||||
#define WEBS_POST 0x4 /* POST without content */
|
||||
#define WEBS_POST_CLEN 0x8 /* Ready to read content for POST */
|
||||
#define WEBS_PROCESSING 0x10 /* Processing request */
|
||||
#define WEBS_KEEP_TIMEOUT 15000 /* Keep-alive timeout (15 secs) */
|
||||
#define WEBS_TIMEOUT 60000 /* General request timeout (60) */
|
||||
|
||||
#define PAGE_READ_BUFSIZE 512 /* bytes read from page files */
|
||||
#define MAX_PORT_LEN 10 /* max digits in port number */
|
||||
#define WEBS_SYM_INIT 64 /* initial # of sym table entries */
|
||||
|
||||
/*
|
||||
* URL handler structure. Stores the leading URL path and the handler
|
||||
* function to call when the URL path is seen.
|
||||
*/
|
||||
typedef struct {
|
||||
int (*handler)(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg,
|
||||
char_t *url, char_t *path,
|
||||
char_t *query); /* Callback URL handler function */
|
||||
char_t *webDir; /* Web directory if required */
|
||||
char_t *urlPrefix; /* URL leading prefix */
|
||||
int len; /* Length of urlPrefix for speed */
|
||||
int arg; /* Argument to provide to handler */
|
||||
int flags; /* Flags */
|
||||
} websUrlHandlerType;
|
||||
|
||||
/*
|
||||
* Webs statistics
|
||||
*/
|
||||
typedef struct {
|
||||
long errors; /* General errors */
|
||||
long redirects;
|
||||
long net_requests;
|
||||
long activeNetRequests;
|
||||
long activeBrowserRequests;
|
||||
long timeouts;
|
||||
long access; /* Access violations */
|
||||
long localHits;
|
||||
long remoteHits;
|
||||
long formHits;
|
||||
long cgiHits;
|
||||
long handlerHits;
|
||||
} websStatsType;
|
||||
|
||||
extern websStatsType websStats; /* Web access stats */
|
||||
|
||||
/*
|
||||
* Error code list
|
||||
*/
|
||||
typedef struct {
|
||||
int code; /* HTTP error code */
|
||||
char_t *msg; /* HTTP error message */
|
||||
} websErrorType;
|
||||
|
||||
/*
|
||||
* Mime type list
|
||||
*/
|
||||
typedef struct {
|
||||
char_t *type; /* Mime type */
|
||||
char_t *ext; /* File extension */
|
||||
} websMimeType;
|
||||
|
||||
/*
|
||||
* File information structure.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned long size; /* File length */
|
||||
int isDir; /* Set if directory */
|
||||
time_t mtime; /* Modified time */
|
||||
} websStatType;
|
||||
|
||||
/*
|
||||
* Compiled Rom Page Index
|
||||
*/
|
||||
typedef struct {
|
||||
char_t *path; /* Web page URL path */
|
||||
unsigned char *page; /* Web page data */
|
||||
int size; /* Size of web page in bytes */
|
||||
int pos; /* Current read position */
|
||||
} websRomPageIndexType;
|
||||
|
||||
/*
|
||||
* Defines for file open.
|
||||
*/
|
||||
#ifndef CE
|
||||
#define SOCKET_RDONLY O_RDONLY
|
||||
#define SOCKET_BINARY O_BINARY
|
||||
#else /* CE */
|
||||
#define SOCKET_RDONLY 0x1
|
||||
#define SOCKET_BINARY 0x2
|
||||
#endif /* CE */
|
||||
|
||||
extern websRomPageIndexType websRomPageIndex[];
|
||||
extern websMimeType websMimeList[]; /* List of mime types */
|
||||
extern sym_fd_t websMime; /* Set of mime types */
|
||||
extern webs_t* webs; /* Session list head */
|
||||
extern int websMax; /* List size */
|
||||
extern char_t websHost[64]; /* Name of this host */
|
||||
extern char_t websIpaddr[64]; /* IP address of this host */
|
||||
extern char_t *websHostUrl; /* URL for this host */
|
||||
extern char_t *websIpaddrUrl; /* URL for this host */
|
||||
extern int websPort; /* Port number */
|
||||
|
||||
/******************************** Prototypes **********************************/
|
||||
|
||||
extern int websAspOpen();
|
||||
extern void websAspClose();
|
||||
extern void websFormOpen();
|
||||
extern void websFormClose();
|
||||
extern int websAspWrite(int ejid, webs_t wp, int argc, char_t **argv);
|
||||
extern void websDefaultClose();
|
||||
extern int websDefaultHandler(webs_t wp, char_t *urlPrefix,
|
||||
char_t *webDir, int arg, char_t *url, char_t *path,
|
||||
char_t *query);
|
||||
extern int websFormHandler(webs_t wp, char_t *urlPrefix, char_t *webDir,
|
||||
int arg, char_t *url, char_t *path, char_t *query);
|
||||
extern int websCgiHandler(webs_t wp, char_t *urlPrefix, char_t *webDir,
|
||||
int arg, char_t *url, char_t *path, char_t *query);
|
||||
extern void websCgiCleanup();
|
||||
extern int websCheckCgiProc(int handle);
|
||||
extern char_t *websGetCgiCommName();
|
||||
|
||||
extern int websLaunchCgiProc(char_t *cgiPath, char_t **argp,
|
||||
char_t **envp, char_t *stdIn, char_t *stdOut);
|
||||
extern int websOpen(int sid);
|
||||
extern void websResponse(webs_t wp, int code, char_t *msg,
|
||||
char_t *redirect);
|
||||
extern int websJavaScriptEval(webs_t wp, char_t *script);
|
||||
extern int websPageReadData(webs_t wp, char *buf, int nBytes);
|
||||
extern int websPageOpen(webs_t wp, char_t *lpath, char_t *path, int mode,
|
||||
int perm);
|
||||
extern void websPageClose(webs_t wp);
|
||||
extern void websPageSeek(webs_t wp, long offset);
|
||||
extern int websPageStat(webs_t wp, char_t *lpath, char_t *path,
|
||||
websStatType *sbuf);
|
||||
extern int websPageIsDirectory(char_t *lpath);
|
||||
extern int websRomOpen();
|
||||
extern void websRomClose();
|
||||
extern int websRomPageOpen(webs_t wp, char_t *path, int mode, int perm);
|
||||
extern void websRomPageClose(int fd);
|
||||
extern int websRomPageReadData(webs_t wp, char *buf, int len);
|
||||
extern int websRomPageStat(char_t *path, websStatType *sbuf);
|
||||
extern long websRomPageSeek(webs_t wp, long offset, int origin);
|
||||
extern void websSetRequestSocketHandler(webs_t wp, int mask,
|
||||
void (*fn)(webs_t wp));
|
||||
extern int websSolutionHandler(webs_t wp, char_t *urlPrefix,
|
||||
char_t *webDir, int arg, char_t *url, char_t *path,
|
||||
char_t *query);
|
||||
extern void websUrlHandlerClose();
|
||||
extern int websUrlHandlerOpen();
|
||||
extern int websOpenServer(int port, int retries);
|
||||
extern void websCloseServer();
|
||||
extern char_t* websGetDateString(websStatType* sbuf);
|
||||
|
||||
extern int strcmpci(char_t* s1, char_t* s2);
|
||||
|
||||
/*
|
||||
* Prototypes for functions available when running as part of the
|
||||
* GoAhead Embedded Management Framework (EMF)
|
||||
*/
|
||||
#ifdef EMF
|
||||
extern int websEmfOpen();
|
||||
extern void websEmfClose();
|
||||
extern void websSetEmfEnvironment(webs_t wp);
|
||||
#endif
|
||||
|
||||
#ifdef CE
|
||||
extern int writeUniToAsc(int fid, void *buf, unsigned int len);
|
||||
extern int readAscToUni(int fid, void **buf, unsigned int len);
|
||||
#endif
|
||||
|
||||
#endif /* _h_WEBS_INTERNAL */
|
||||
|
||||
/******************************************************************************/
|
||||
Reference in New Issue
Block a user