mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-10 09:33:46 +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