diff options
author | cvsadm <cvsadm> | 2005-01-21 00:44:34 +0000 |
---|---|---|
committer | cvsadm <cvsadm> | 2005-01-21 00:44:34 +0000 |
commit | b2093e3016027d6b5cf06b3f91f30769bfc099e2 (patch) | |
tree | cf58939393a9032182c4fbc4441164a9456e82f8 /lib/base | |
download | ds-ldapserver7x.tar.gz ds-ldapserver7x.tar.xz ds-ldapserver7x.zip |
Moving NSCP Directory Server from DirectoryBranch to TRUNK, initial drop. (foxworth)ldapserver7x
Diffstat (limited to 'lib/base')
-rw-r--r-- | lib/base/Makefile | 111 | ||||
-rw-r--r-- | lib/base/crit.cpp | 399 | ||||
-rw-r--r-- | lib/base/dns.cpp | 176 | ||||
-rw-r--r-- | lib/base/dnsdmain.cpp | 159 | ||||
-rw-r--r-- | lib/base/ereport.cpp | 249 | ||||
-rw-r--r-- | lib/base/eventlog.cpp | 70 | ||||
-rw-r--r-- | lib/base/file.cpp | 702 | ||||
-rw-r--r-- | lib/base/fsmutex.cpp | 187 | ||||
-rw-r--r-- | lib/base/lexer.cpp | 978 | ||||
-rw-r--r-- | lib/base/lexer_pvt.h | 30 | ||||
-rw-r--r-- | lib/base/net.cpp | 578 | ||||
-rw-r--r-- | lib/base/nscperror.c | 162 | ||||
-rw-r--r-- | lib/base/nterrors.cpp | 83 | ||||
-rw-r--r-- | lib/base/plist.cpp | 1154 | ||||
-rw-r--r-- | lib/base/plist_pvt.h | 122 | ||||
-rw-r--r-- | lib/base/pool.cpp | 654 | ||||
-rw-r--r-- | lib/base/rwlock.cpp | 131 | ||||
-rw-r--r-- | lib/base/shexp.cpp | 290 | ||||
-rw-r--r-- | lib/base/shmem.cpp | 127 | ||||
-rw-r--r-- | lib/base/system.cpp | 264 | ||||
-rw-r--r-- | lib/base/systhr.cpp | 256 | ||||
-rw-r--r-- | lib/base/util.cpp | 1449 |
22 files changed, 8331 insertions, 0 deletions
diff --git a/lib/base/Makefile b/lib/base/Makefile new file mode 100644 index 00000000..f58195d3 --- /dev/null +++ b/lib/base/Makefile @@ -0,0 +1,111 @@ +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +# The base library contains the base set of functionality for ldapserver +# servers. Cross-platform I/O and other generic functions are +# provided here. + + +MCOM_ROOT=../../.. +MODULE=LibBase + +include ../../nsdefs.mk + +OBJDEST=$(OBJDIR)/lib/base + +ifeq ($(ARCH), WINNT) +LIBS=$(OBJDIR)/lib/libbase.lib +ifeq ($(BSCINFO), yes) +BSCS=$(OBJDIR)/lib/libbase.bsc +endif +else +LIBS=$(OBJDIR)/lib/libbase.a +endif + +include ../../nsconfig.mk + +MCC_INCLUDE += $(ADMINUTIL_INCLUDE) + +LOCAL_DEPS = $(NSPR_DEP) $(ADMINUTIL_DEP) $(SECURITY_DEP) $(DBM_DEP) + +all: $(LOCAL_DEPS) $(OBJDEST) $(LIBS) $(BSCS) + +$(OBJDEST): + mkdir -p $(OBJDEST) + +ifeq ($(ARCH), WINNT) +OSOBJS = nterrors.o eventlog.o eventhandler.o ntpipe.o pathnames.o +else +OSOBJS = +endif + +OBJS = $(addprefix $(OBJDEST)/, \ + dstats.o \ + daemon.o \ + shexp.o \ + regexp.o \ + pblock.o \ + plist.o \ + buffer.o \ + netbuf.o \ + file.o \ + net.o \ + session.o \ + cinfo.o \ + util.o \ + ereport.o \ + sem.o \ + fsmutex.o \ + systhr.o \ + crit.o \ + rwlock.o \ + dns.o \ + dnsdmain.o \ + shmem.o \ + dll.o \ + servssl.o \ + lexer.o \ + restart.o \ + objndx.o \ + cache.o \ + pool.o \ + time_cache.o \ + dns_cache.o \ + system.o \ + xp.o \ + nscperror.o \ + language.o \ + fasttime.o \ + secpwd.o \ + $(OSOBJS) \ + ) + +MODULE_CFLAGS=-I$(NSROOT)/include/base + +ifeq ($(PRODUCT),"Netscape Catalog Server") +ifeq ($(ARCH), WINNT) +MCC_INCLUDE := $(subst -I$(MCOM_ROOT)/lib/libnet,,$(MCC_INCLUDE)) +endif +endif + +#$(OBJDEST)/fasttime.o : $(OBJDIR)/fasttime.o +# cp $< $@ + +$(LIBS): $(OBJS) + rm -f $@ + $(AR) $(OBJS) + $(RANLIB) $@ + +ifeq ($(ARCH), WINNT) +ifeq ($(BSCINFO), yes) +$(BSCS): $(OBJS) + $(BSCMAKE) $(OBJDEST)/*.sbr +endif +endif + +include $(INCLUDE_DEPENDS) + diff --git a/lib/base/crit.cpp b/lib/base/crit.cpp new file mode 100644 index 00000000..06f5fba4 --- /dev/null +++ b/lib/base/crit.cpp @@ -0,0 +1,399 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * crit.c: Critical section abstraction. Used in threaded servers to protect + * areas where two threads can interfere with each other. + * + * Condvars are condition variables that are used for thread-thread + * synchronization. + * + * Rob McCool + */ + +#include "systems.h" + +#include "netsite.h" +#include "crit.h" +#include "pool.h" +#include "ereport.h" + +#include "base/dbtbase.h" + +#ifdef USE_NSPR +/* +#include "prmon.h" +#include "private/primpl.h" +*/ +#include "nspr.h" + +/* private/primpl.h is gone fromnspr21 19971028 */ +#if 0 +#ifdef XP_WIN32 +#include "private/primpl.h" +#endif /* XP_WIN32 */ +#endif + +#include "prthread.h" +#include "prlock.h" +#include "prcvar.h" +#include "prinrval.h" + +/* + * Defined to replace PR_Monitor() with PR_Lock(). + */ +typedef struct critical { + PRLock *lock; + PRUint32 count; + PRThread *owner; +} critical_t; + +typedef struct condvar { + critical_t *lock; + PRCondVar *cvar; +} condvar_t; + +#endif +/* -------------------------- critical sections --------------------------- */ + +/* Useful for ASSERTs only. Returns non-zero if the current thread is the owner. + */ +NSAPI_PUBLIC int crit_owner_is_me(CRITICAL id) +{ +#ifdef USE_NSPR + critical_t *crit = (critical_t*)id; + + return (crit->owner == PR_GetCurrentThread()); +#else + return 1; +#endif +} + +NSAPI_PUBLIC CRITICAL crit_init(void) +{ +#ifdef USE_NSPR + critical_t *crit = (critical_t*)PERM_MALLOC(sizeof(critical_t)) ; + + if (crit) { + if (!(crit->lock = PR_NewLock())) { + PERM_FREE(crit); + return NULL; + } + crit->count = 0; + crit->owner = 0; + } + return (void *) crit; +#else + return NULL; +#endif +} + +NSAPI_PUBLIC void crit_enter(CRITICAL id) +{ +#ifdef USE_NSPR + critical_t *crit = (critical_t*)id; + PRThread *me = PR_GetCurrentThread(); + + if ( crit->owner == me) { + NS_ASSERT(crit->count > 0); + crit->count++; + } + else { + PR_Lock(crit->lock); + NS_ASSERT(crit->count == 0); + crit->count = 1; + crit->owner = me; + } +#endif +} + +NSAPI_PUBLIC void crit_exit(CRITICAL id) +{ +#ifdef USE_NSPR + critical_t *crit = (critical_t*)id; + + if (crit->owner != PR_GetCurrentThread()) + return; + + if ( --crit->count == 0) { + crit->owner = 0; + PR_Unlock(crit->lock); + } + NS_ASSERT(crit->count >= 0); +#endif +} + +NSAPI_PUBLIC void crit_terminate(CRITICAL id) +{ +#ifdef USE_NSPR + critical_t *crit = (critical_t*)id; + + PR_DestroyLock((PRLock*)crit->lock); + PERM_FREE(crit); +#endif +} + + +/* ------------------------- condition variables -------------------------- */ + + +NSAPI_PUBLIC CONDVAR condvar_init(CRITICAL id) +{ +#ifdef USE_NSPR + critical_t *crit = (critical_t*)id; + + condvar_t *cvar = (condvar_t*)PERM_MALLOC(sizeof(condvar_t)) ; + + if (crit) { + cvar->lock = crit; + if ((cvar->cvar = PR_NewCondVar((PRLock *)cvar->lock->lock)) == 0) { + PERM_FREE(cvar); + return NULL; + } + } + return (void *) cvar; +#endif +} + +NSAPI_PUBLIC void condvar_wait(CONDVAR _cv) +{ +#ifdef USE_NSPR + condvar_t *cv = (condvar_t *)_cv; + /* Save away recursion count so we can restore it after the wait */ + int saveCount = cv->lock->count; + PRThread *saveOwner = cv->lock->owner; + + NS_ASSERT(cv->lock->owner == PR_GetCurrentThread()); + cv->lock->count = 0; + cv->lock->owner = 0; + + PR_WaitCondVar(cv->cvar, PR_INTERVAL_NO_TIMEOUT); + + cv->lock->count = saveCount; + cv->lock->owner = saveOwner; +#endif +} + + +NSAPI_PUBLIC void condvar_timed_wait(CONDVAR _cv, long secs) +{ +#ifdef USE_NSPR + condvar_t *cv = (condvar_t *)_cv; + /* Save away recursion count so we can restore it after the wait */ + int saveCount = cv->lock->count; + PRThread *saveOwner = cv->lock->owner; + + NS_ASSERT(cv->lock->owner == PR_GetCurrentThread()); + cv->lock->count = 0; + cv->lock->owner = 0; + + PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT; + if (secs > 0) + timeout = PR_SecondsToInterval(secs); + PR_WaitCondVar(cv->cvar, timeout); + + cv->lock->count = saveCount; + cv->lock->owner = saveOwner; +#endif +} + + + +NSAPI_PUBLIC void condvar_notify(CONDVAR _cv) +{ +#ifdef USE_NSPR + condvar_t *cv = (condvar_t *)_cv; + NS_ASSERT(cv->lock->owner == PR_GetCurrentThread()); + PR_NotifyCondVar(cv->cvar); +#endif +} + +NSAPI_PUBLIC void condvar_notifyAll(CONDVAR _cv) +{ +#ifdef USE_NSPR + condvar_t *cv = (condvar_t *)_cv; + NS_ASSERT(cv->lock->owner == PR_GetCurrentThread()); + PR_NotifyAllCondVar(cv->cvar); +#endif +} + +NSAPI_PUBLIC void condvar_terminate(CONDVAR _cv) +{ +#ifdef USE_NSPR + condvar_t *cv = (condvar_t *)_cv; + PR_DestroyCondVar(cv->cvar); + PERM_FREE(cv); +#endif +} + +/* ----------------------- Counting semaphores ---------------------------- */ +/* These are currently not listed in crit.h because they aren't yet used; + * although they do work. + */ + +/* + * XXXMB - these should be in NSPR. + * + */ + +#if defined(SOLARIS) && defined(HW_THREADS) +#include <synch.h> +typedef sema_t counting_sem_t; +#elif defined(IRIX) && defined(HW_THREADS) +#include <ulocks.h> +typedef usema_t *counting_sem_t; +#else +typedef struct counting_sem_t { + CRITICAL lock; + CRITICAL cv_lock; + CONDVAR cv; + int count; + int max; +} counting_sem_t; +#endif + +NSAPI_PUBLIC COUNTING_SEMAPHORE +cs_init(int initial_count) +{ + counting_sem_t *cs = (counting_sem_t *)PERM_MALLOC(sizeof(counting_sem_t)); +#if defined(SOLARIS) && defined(HW_THREADS) + if ( sema_init(cs, initial_count, USYNC_THREAD, NULL) < 0) { + ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csInitFailureS_), system_errmsg()); + PERM_FREE(cs); + return NULL; + } + + return (COUNTING_SEMAPHORE)cs; +#elif defined(IRIX) && defined(HW_THREADS) + usptr_t *arena; + + usconfig(CONF_INITSIZE, 64*1024); + if ( (arena = usinit("/tmp/cs.locks")) == NULL) + return NULL; + + if ( (cs = (counting_sem_t *)usnewsema(arena, 0)) == NULL) + return NULL; + + return cs; + +#else + + cs->count = initial_count; + cs->lock = crit_init(); + cs->cv_lock = crit_init(); + cs->cv = condvar_init(cs->cv_lock); + + return (COUNTING_SEMAPHORE)cs; +#endif +} + +NSAPI_PUBLIC void +cs_terminate(COUNTING_SEMAPHORE csp) +{ + counting_sem_t *cs = (counting_sem_t *)csp; + +#if defined(SOLARIS) && defined(HW_THREADS) + if ( sema_destroy(cs) < 0 ) { + ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csTerminateFailureS_), system_errmsg()); + } + PERM_FREE(cs); + return; +#elif defined(IRIX) && defined(HW_THREADS) + /* usfreesema() */ + return; +#else + condvar_terminate(cs->cv); + crit_terminate(cs->cv_lock); + crit_terminate(cs->lock); + PERM_FREE(cs); + + return; +#endif +} + +NSAPI_PUBLIC int +cs_wait(COUNTING_SEMAPHORE csp) +{ + counting_sem_t *cs = (counting_sem_t *)csp; + int ret; + +#if defined(SOLARIS) && defined(HW_THREADS) + if ( (ret = sema_wait(cs)) < 0 ) { + ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csWaitFailureS_), system_errmsg()); + return -1; + } + return ret; +#elif defined(IRIX) && defined(HW_THREADS) + uspsema(cs); + return 0; +#else + crit_enter(cs->lock); + while ( cs->count == 0 ) { + crit_enter(cs->cv_lock); + crit_exit(cs->lock); + condvar_wait(cs->cv); + crit_exit(cs->cv_lock); + crit_enter(cs->lock); + } + ret = --(cs->count); + crit_exit(cs->lock); + + return 0; +#endif +} + +NSAPI_PUBLIC int +cs_trywait(COUNTING_SEMAPHORE csp) +{ + counting_sem_t *cs = (counting_sem_t *)csp; + int ret; + +#if defined(SOLARIS) && defined(HW_THREADS) + ret = sema_trywait(cs)?-1:0; + return ret; +#elif defined(IRIX) && defined(HW_THREADS) + ret = uscpsema(cs); + return (ret == 1)?0:-1; +#else + crit_enter(cs->lock); + if (cs->count > 0) { + ret = --(cs->count); + crit_exit(cs->lock); + return 0; + } + crit_exit(cs->lock); + return -1; + +#endif +} + +NSAPI_PUBLIC int +cs_release(COUNTING_SEMAPHORE csp) +{ + counting_sem_t *cs = (counting_sem_t *)csp; + int ret; + +#if defined(SOLARIS) && defined(HW_THREADS) + if ( (ret = sema_post(cs)) < 0 ) { + ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csPostFailureS_), system_errmsg()); + return -1; + } + return ret; +#elif defined(IRIX) && defined(HW_THREADS) + usvsema(cs); + return 0; +#else + crit_enter(cs->lock); + ret = ++(cs->count); + if (cs->count == 1) { + crit_enter(cs->cv_lock); + condvar_notify(cs->cv); + crit_exit(cs->cv_lock); + } + crit_exit(cs->lock); + + return 0; +#endif +} diff --git a/lib/base/dns.cpp b/lib/base/dns.cpp new file mode 100644 index 00000000..f9e38886 --- /dev/null +++ b/lib/base/dns.cpp @@ -0,0 +1,176 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * dns.c: DNS resolution routines + * + * Rob McCool + */ +#define DNS_GUESSING + +#include "netsite.h" +#ifdef XP_UNIX +#include "systems.h" +#else /* XP_WIN32 */ +#include "base/systems.h" +#endif /* XP_WIN32 */ + +#include "net.h" /* SYS_NETFD, various headers to do DNS */ + +/* Under NT, these are taken care of by net.h including winsock.h */ +#ifdef XP_UNIX +#include <arpa/inet.h> /* inet_ntoa */ +#include <netdb.h> /* struct hostent */ +#ifdef NEED_GHN_PROTO +extern "C" int gethostname (char *name, size_t namelen); +#endif +#endif +#ifdef DNS_CACHE +#include "base/dns_cache.h" +#include "base/ereport.h" +#endif /* DNS_CACHE */ +#include <stdio.h> +#include <nspr.h> +#include "frame/conf.h" + +/* ---------------------------- dns_find_fqdn ----------------------------- */ + + +/* defined in dnsdmain.c */ +extern "C" NSAPI_PUBLIC char *dns_guess_domain(char * hname); + +char *net_find_fqdn(PRHostEnt *p) +{ + int x; + + if((!p->h_name) || (!p->h_aliases)) + return NULL; + + if(!strchr(p->h_name, '.')) { + for(x = 0; p->h_aliases[x]; ++x) { + if((strchr(p->h_aliases[x], '.')) && + (!strncmp(p->h_aliases[x], p->h_name, strlen(p->h_name)))) + { + return STRDUP(p->h_aliases[x]); + } + } +#ifdef DNS_GUESSING + return dns_guess_domain(p->h_name); +#else + return NULL; +#endif /* DNS_GUESSING */ + } + else + return STRDUP(p->h_name); +} + + +/* ----------------------------- dns_ip2host ------------------------------ */ + + +char *dns_ip2host(char *ip, int verify) +{ + /* struct in_addr iaddr; */ + PRNetAddr iaddr; + char *hn; +#ifdef DNS_CACHE + dns_cache_entry_t *dns_entry; +#endif + static unsigned long laddr = 0; + static char myhostname[256]; + PRHostEnt hent; + char buf[PR_NETDB_BUF_SIZE]; + PRStatus err; + + + err = PR_InitializeNetAddr(PR_IpAddrNull, 0, &iaddr); + + if((iaddr.inet.ip = inet_addr(ip)) == -1) + goto bong; + +#ifdef DNS_CACHE + if ( (dns_entry = dns_cache_lookup_ip((unsigned int)iaddr.inet.ip)) ) { + hn = NULL; + if ( dns_entry->host && + /* Only use entry if the cache entry has been verified or if + * verify is off... + */ + (dns_entry->verified || !verify) ) { + hn = STRDUP( dns_entry->host ); + (void)dns_cache_use_decrement(dns_entry); + return hn; + } + dns_cache_delete(dns_entry); + dns_entry = 0; + } +#endif + + /* + * See if it happens to be the localhost IP address, and try + * the local host name if so. + */ + if (laddr == 0) { + laddr = inet_addr("127.0.0.1"); + myhostname[0] = 0; + PR_GetSystemInfo(PR_SI_HOSTNAME, myhostname, sizeof(myhostname)); + } + + /* Have to match the localhost IP address and have a hostname */ + if ((iaddr.inet.ip == laddr) && (myhostname[0] != 0)) { + /* + * Now try for a fully-qualified domain name, starting with + * the local hostname. + */ + err = PR_GetHostByName(myhostname, + buf, + PR_NETDB_BUF_SIZE, + &hent); + + /* Don't verify if we get a fully-qualified name this way */ + verify = 0; + } + else { + err = PR_GetHostByAddr(&iaddr, + buf, + PR_NETDB_BUF_SIZE, + &hent); + } + + if ((err == PR_FAILURE) || !(hn = net_find_fqdn(&hent))) goto bong; + + + if(verify) { + char **haddr = 0; + err = PR_GetHostByName(hn, + buf, + PR_NETDB_BUF_SIZE, + &hent); + + if(err == PR_SUCCESS) { + for(haddr = hent.h_addr_list; *haddr; haddr++) { + if(((struct in_addr *)(*haddr))->s_addr == iaddr.inet.ip) + break; + } + } + + if((err == PR_FAILURE) || (!(*haddr))) + goto bong; + } + +#ifdef DNS_CACHE + if ( (dns_entry = dns_cache_insert(hn, (unsigned int)iaddr.inet.ip, verify)) ) { + (void) dns_cache_use_decrement(dns_entry); + } +#endif /* DNS_CACHE */ + return hn; + bong: +#ifdef DNS_CACHE + /* Insert the lookup failure */ + if ( (dns_entry = dns_cache_insert(NULL, (unsigned int)iaddr.inet.ip, verify)) ) { + (void) dns_cache_use_decrement(dns_entry); + } +#endif /* DNS_CACHE */ + return NULL; +} diff --git a/lib/base/dnsdmain.cpp b/lib/base/dnsdmain.cpp new file mode 100644 index 00000000..f37e475c --- /dev/null +++ b/lib/base/dnsdmain.cpp @@ -0,0 +1,159 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * dnsdmain.c: DNS domain guessing stuff moved out of dns.c because of the + * string ball problems + */ + + +#include "netsite.h" +#include "base/net.h" +#include <string.h> +#include <stdio.h> +#ifdef XP_UNIX +#include <unistd.h> +#endif +#include <ctype.h> +#include "util.h" + +/* Under NT, this is taken care of by net.h including winsock.h */ +#ifdef XP_UNIX +#include <netdb.h> /* struct hostent */ +#endif +extern "C" { +#include <nspr.h> +} +#include "frame/conf.h" + + + +/* This is contained in resolv.h on most systems. */ +#define _PATH_RESCONF "/etc/resolv.conf" + +#ifdef XP_UNIX +NSPR_BEGIN_EXTERN_C +#ifdef Linux +extern int getdomainname(char *, size_t); +#else +extern int getdomainname(char *, int); +#endif /* Linux */ +#if defined(HPUX) || defined (UnixWare) || defined(Linux) || defined(IRIX6_5) +extern int gethostname (char *name, size_t namelen); +#else +#ifndef AIX +extern int gethostname (char *name, int namelen); +#endif +#endif +NSPR_END_EXTERN_C +#endif + + +/* ---------------------------- dns_guess_domain -------------------------- */ + + +extern "C" NSAPI_PUBLIC char *dns_guess_domain(char * hname) +{ + FILE *f; + char * cp; + int hnlen; + char line[256]; + static int dnlen = 0; + static char * domain = 0; + PRHostEnt hent; + char buf[PR_NETDB_BUF_SIZE]; + PRStatus err; + + /* Sanity check */ + if (strchr(hname, '.')) { + return STRDUP(hname); + } + + if (dnlen == 0) { + + /* First try a little trick that seems to often work... */ + + /* + * Get the local host name, even it doesn't come back + * fully qualified. + */ + line[0] = 0; + gethostname(line, sizeof(line)); + if (line[0] != 0) { + /* Is it fully qualified? */ + domain = strchr(line, '.'); + if (domain == 0) { + /* No, try gethostbyname() */ + err = PR_GetHostByName(line, + buf, + PR_NETDB_BUF_SIZE, + &hent); + if (err == PR_SUCCESS) { + /* See if h_name is fully-qualified */ + if (hent.h_name) domain = strchr(hent.h_name, '.'); + + /* Otherwise look for a fully qualified alias */ + if ((domain == 0) && + (hent.h_aliases && hent.h_aliases[0])) { + char **p; + for (p = hent.h_aliases; *p; ++p) { + domain = strchr(*p, '.'); + if (domain) break; + } + } + } + } + } + + /* Still no luck? */ + if (domain == 0) { + + f = fopen(_PATH_RESCONF, "r"); + + /* See if there's a domain entry in their resolver configuration */ + if(f) { + while(fgets(line, sizeof(line), f)) { + if(!strncasecmp(line, "domain ", 7)) { + for (cp = &line[7]; *cp && isspace(*cp); ++cp) ; + if (*cp) { + domain = cp; + for (; *cp && !isspace(*cp); ++cp) ; + *cp = 0; + } + break; + } + } + fclose(f); + } + } + +#ifndef NO_DOMAINNAME + if (domain == 0) { + /* No domain found. Try getdomainname. */ + getdomainname(line, sizeof(line)); + if (line[0] != 0) domain = &line[0]; + } +#endif + + if (domain != 0) { + if (domain[0] == '.') ++domain; + domain = STRDUP(domain); + dnlen = strlen(domain); + } + else dnlen = -1; + } + + if (domain != 0) { + hnlen = strlen(hname); + if ((hnlen + dnlen + 2) <= sizeof(line)) { + strcpy(line, hname); + line[hnlen] = '.'; + strcpy(&line[hnlen+1], domain); + return STRDUP(line); + } + } + + return 0; +} diff --git a/lib/base/ereport.cpp b/lib/base/ereport.cpp new file mode 100644 index 00000000..3454d01f --- /dev/null +++ b/lib/base/ereport.cpp @@ -0,0 +1,249 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * ereport.c: Records transactions, reports errors to administrators, etc. + * + * Rob McCool + */ + + +#include "private/pprio.h" /* for nspr20 binary release */ +#include "netsite.h" +#include "file.h" /* system_fopenWA, system_write_atomic */ +#include "pblock.h" +#include "session.h" +#include "util.h" /* util_vsprintf */ +#include "ereport.h" + +#include "base/dbtbase.h" + +#include <stdarg.h> +#include <stdio.h> /* vsprintf */ +#include <string.h> /* strcpy */ +#include <time.h> /* localtime */ + +#ifdef XP_UNIX +#include <syslog.h> /* error logging to syslog */ + +static SYS_FILE _error_fd; +#else /* WIN32 */ +#include <nt/regparms.h> +#include <nt/messages.h> +#include "eventlog.h" + +static SYS_FILE _error_fd; +#endif /* XP_UNIX */ + +static PRBool _ereport_initialized = PR_FALSE; + + +NSAPI_PUBLIC SYS_FILE ereport_getfd(void) { return _error_fd; } + + + +/* ----------------------------- ereport_init ----------------------------- */ + + +NSAPI_PUBLIC char *ereport_init(char *err_fn, char *email, + PASSWD pwuser, char *version) +{ + char err[MAGNUS_ERROR_LEN]; + SYS_FILE new_fd; + +#ifdef XP_UNIX + if(!strcmp(err_fn, "SYSLOG")) { +#ifdef NET_SSL + openlog("secure-httpd", LOG_PID, LOG_DAEMON); +#else + openlog("httpd", LOG_PID, LOG_DAEMON); +#endif + _error_fd = PR_ImportFile(ERRORS_TO_SYSLOG); + + _ereport_initialized = PR_TRUE; + return NULL; + } +#endif /* XP_UNIX */ + if( (new_fd = system_fopenWA(err_fn)) == SYS_ERROR_FD) { + util_snprintf(err, MAGNUS_ERROR_LEN, "can't open error log %s (%s)", err_fn, + system_errmsg()); +#ifdef XP_UNIX + _error_fd = PR_ImportFile(STDERR_FILENO); +#else + _error_fd = PR_ImportFile(NULL); +#endif + return STRDUP(err); + } + _error_fd = new_fd; + +#ifdef XP_UNIX + if(pwuser) + chown(err_fn, pwuser->pw_uid, pwuser->pw_gid); +#endif /* XP_UNIX */ + + _ereport_initialized = PR_TRUE; + + ereport(LOG_INFORM, XP_GetAdminStr(DBT_successfulServerStartup_)); + ereport(LOG_INFORM, XP_GetAdminStr(DBT_SBS_), MAGNUS_VERSION_STRING, BUILD_NUM); + if (strcasecmp(BUILD_NUM, version)) { + ereport(LOG_WARN, XP_GetAdminStr(DBT_netscapeExecutableAndSharedLibra_)); + ereport(LOG_WARN, XP_GetAdminStr(DBT_executableVersionIsS_), version); + ereport(LOG_WARN, XP_GetAdminStr(DBT_sharedLibraryVersionIsS_), BUILD_NUM); + + } + + /* Initialize thread-specific error handling */ + system_errmsg_init(); + + return NULL; +} + + + +/* -------------------------- ereport_terminate --------------------------- */ + + +NSAPI_PUBLIC void ereport_terminate(void) +{ + if (!_ereport_initialized) + return; + +#ifdef XP_UNIX + ereport(LOG_INFORM, XP_GetAdminStr(DBT_errorReportingShuttingDown_)); + if(PR_FileDesc2NativeHandle(_error_fd) != ERRORS_TO_SYSLOG) + system_fclose(_error_fd); + else + closelog(); +#else /* WIN32 */ + if(PR_FileDesc2NativeHandle(_error_fd) != NULL) + system_fclose(_error_fd); +#endif /* XP_UNIX */ + +} + + +/* ------------------------------- ereport -------------------------------- */ + + +static int degree_msg[] = { + DBT_warning_, + DBT_config_, + DBT_security_, + DBT_failure_, + DBT_catastrophe_, + DBT_info_, + DBT_verbose_ + }; + +#ifdef XP_UNIX +static int degree_syslog[] = { + LOG_WARNING, LOG_ERR, LOG_NOTICE, LOG_ALERT, LOG_CRIT, LOG_INFO, LOG_INFO +}; +#endif/* XP_UNIX */ + + +NSAPI_PUBLIC int ereport_v(int degree, char *fmt, va_list args) +{ + char errstr[MAX_ERROR_LEN]; + int pos = 0; + struct tm *tms, tmss; + time_t t; +#ifdef MCC_PROXY + char *p; + int i; +#endif /* MCC_PROXY */ + + if (!_ereport_initialized) + return IO_OKAY; + +#ifdef XP_UNIX + if(PR_FileDesc2NativeHandle(_error_fd) != ERRORS_TO_SYSLOG) { +#endif /* XP_UNIX */ + t = time(NULL); + tms = system_localtime(&t, &tmss); + util_strftime(errstr, ERR_TIMEFMT, tms); + pos = strlen(errstr); + + pos += util_snprintf(&errstr[pos], MAX_ERROR_LEN - pos, " %s: ", + XP_GetAdminStr(degree_msg[degree])); +#ifdef XP_UNIX + } +#endif /* XP_UNIX */ + + pos += util_vsnprintf(&errstr[pos], sizeof(errstr) - pos, fmt, args); + + pos += util_snprintf(&errstr[pos], sizeof(errstr) - pos, ENDLINE); + +#ifdef MCC_PROXY + /* Thanx to netlib, the proxy sometimes generates multiline err msgs */ + for(p=errstr, i=pos-1; i>0; i--, p++) { + if (*p == '\n' || *p == '\r') *p = ' '; + } +#endif /* MCC_PROXY */ + +#if defined XP_UNIX + if(PR_FileDesc2NativeHandle(_error_fd) != ERRORS_TO_SYSLOG) + return system_fwrite_atomic(_error_fd, errstr, pos); + syslog(degree_syslog[degree], errstr); + return IO_OKAY; +#elif defined XP_WIN32 /* XP_WIN32 */ + if(PR_FileDesc2NativeHandle(_error_fd) != NULL) + { +#ifdef MCC_HTTPD + /* also write to NT Event Log if error is serious */ + switch (degree) + { + case LOG_MISCONFIG: + case LOG_SECURITY: + case LOG_CATASTROPHE: + LogErrorEvent(NULL, EVENTLOG_ERROR_TYPE, + 0, MSG_BAD_PARAMETER, + errstr, NULL); + break; + default: + break; + } +#endif + return system_fwrite_atomic(_error_fd, errstr, pos); + } + else { /* log to the EventLogger */ + /* Write to the event logger... */ + switch (degree) { + case LOG_WARN: + LogErrorEvent(NULL, EVENTLOG_WARNING_TYPE, + 0, MSG_BAD_PARAMETER, + errstr, NULL); + break; + case LOG_MISCONFIG: + case LOG_SECURITY: + case LOG_FAILURE: + case LOG_CATASTROPHE: + LogErrorEvent(NULL, EVENTLOG_ERROR_TYPE, + 0, MSG_BAD_PARAMETER, + errstr, NULL); + break; + + case LOG_INFORM: + default: + LogErrorEvent(NULL, EVENTLOG_INFORMATION_TYPE, + 0, MSG_BAD_PARAMETER, + errstr, NULL); + break; + } + return (IO_OKAY); + } +#endif /* XP_WIN32 */ + +} + +NSAPI_PUBLIC int ereport(int degree, char *fmt, ...) +{ + va_list args; + int rv; + va_start(args, fmt); + rv = ereport_v(degree, fmt, args); + va_end(args); + return rv; +} diff --git a/lib/base/eventlog.cpp b/lib/base/eventlog.cpp new file mode 100644 index 00000000..b8762842 --- /dev/null +++ b/lib/base/eventlog.cpp @@ -0,0 +1,70 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +// // +// Name: EVENTLOG // +// Platforms: WIN32 // +// ...................................................................... // +// Revision History: // +// 01-12-95 Initial Version, Aruna Victor (aruna@netscape.com) // +// 12-02-96 Code cleanup, Andy Hakim (ahakim@netscape.com) // +// - consolidated admin and http functions into one // +// - moved registry modification code to installer // +// - removed several unecessary functions // +// - changed function parameters to existing functions // +// // +//--------------------------------------------------------------------------// + +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include "netsite.h" +#include "base/eventlog.h" +#include "frame/conf.h" +#include <nt/regparms.h> +#include <nt/messages.h> + +HANDLE ghEventSource; + +NSPR_BEGIN_EXTERN_C + +NSAPI_PUBLIC HANDLE InitializeLogging(char *szEventLogName) +{ + ghEventSource = RegisterEventSource(NULL, szEventLogName); + return ghEventSource; +} + + + +NSAPI_PUBLIC BOOL TerminateLogging(HANDLE hEventSource) +{ + BOOL bReturn = FALSE; + if(hEventSource == NULL) + hEventSource = ghEventSource; + if(hEventSource) + bReturn = DeregisterEventSource(hEventSource); + return(bReturn); +} + + + +NSAPI_PUBLIC BOOL LogErrorEvent(HANDLE hEventSource, WORD fwEventType, WORD fwCategory, DWORD IDEvent, LPTSTR chMsg, LPTSTR lpszMsg) +{ + BOOL bReturn = FALSE; + LPTSTR lpszStrings[2]; + + lpszStrings[0] = chMsg; + lpszStrings[1] = lpszMsg; + + if(hEventSource == NULL) + hEventSource = ghEventSource; + + if(hEventSource) + bReturn = ReportEvent(hEventSource, fwEventType, fwCategory, + IDEvent, NULL, 2, 0, (LPCTSTR *)lpszStrings, NULL); + return(bReturn); +} + +NSPR_END_EXTERN_C diff --git a/lib/base/file.cpp b/lib/base/file.cpp new file mode 100644 index 00000000..7382be46 --- /dev/null +++ b/lib/base/file.cpp @@ -0,0 +1,702 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * file.c: system specific functions for reading/writing files + * + * See file.h for formal definitions of what these functions do + * + * Rob McCool + */ + + +#include "base/file.h" +#include "ereport.h" +#ifdef BSD_RLIMIT +#include <sys/time.h> +#include <sys/resource.h> +#else +#include <stdlib.h> +#include <signal.h> +#endif +#ifdef XP_WIN32 +#include <time.h> /* time */ +#include <sys/stat.h> /* stat */ +#include <errno.h> +#include <direct.h> +#include <base/nterr.h> +/* Removed for ns security integration +#include <xp_error.h> +*/ +#endif +#include <prerror.h> + +#include "private/pprio.h" +#include "prlock.h" + +extern "C" char *nscperror_lookup(int err); + +/* --- globals -------------------------------------------------------------*/ +/* PRFileDesc * SYS_ERROR_FD = NULL; */ + +const int errbuf_size = 256; +const unsigned int LOCKFILERANGE=0x7FFFFFFF; +PRLock *_atomic_write_lock = NULL; + +/* --------------------------------- stat --------------------------------- */ + + + /* XXXMB - Can't convert to PR_GetFileInfo because we directly exported + * the stat interface... Damn. + */ +NSAPI_PUBLIC int system_stat(char *path, struct stat *finfo) +{ +#ifdef XP_WIN32 + + int chop, l; + +/* The NT stat is very peculiar about directory names. */ +/* XXX aruna - there is a bug here, maybe in the C runtime. + * Stating the same path in a separate program succeeds. From + * jblack's profiling, this needs to be replaced by the Win32 + * calls anyway.*/ + + l = strlen(path); + if((path[l - 1] == '/') && + (!(isalpha(path[0]) && (!strcmp(&path[1], ":/"))))) + { + chop = 1; + path[--l] = '\0'; + } + else chop = 0; +#endif /* XP_WIN32 */ + +#ifdef XP_UNIX + if(stat(path, finfo) == -1) + return -1; +#else /* XP_WIN32 */ + + if(_stat(path, (struct _stat *)finfo) == -1) { + /* XXXMB - this sucks; + * try to convert to an error code we'll expect... + */ + switch(errno) { + case ENOENT: PR_SetError(PR_FILE_NOT_FOUND_ERROR, errno); break; + default: PR_SetError(PR_UNKNOWN_ERROR, errno); break; + } + return -1; + } + + /* NT sets the time fields to -1 if it thinks that the file + * is a device ( like com1.html, lpt1.html etc) In this case + * simply set last modified time to the current time.... + */ + + if (finfo->st_mtime == -1) { + finfo->st_mtime = time(NULL); + } + if (finfo->st_atime == -1) { + finfo->st_atime = 0; + } + if (finfo->st_ctime == -1) { + finfo->st_ctime = 0; + } + if(chop) + path[l++] = '/'; + +#endif /* XP_WIN32 */ + + if(S_ISREG(finfo->st_mode) && (path[strlen(path) - 1] == '/')) { + /* File with trailing slash */ + errno = ENOENT; + return -1; + } + return 0; +} + + +NSAPI_PUBLIC int system_fread(SYS_FILE fd, char *buf, int sz) +{ + /* XXXMB - this is the *one* function which does return a length + * instead of the IO_ERROR/IO_OKAY. + */ + return PR_Read(fd, buf, sz); +} + +NSAPI_PUBLIC int system_fwrite(SYS_FILE fd, char *buf, int sz) { + int n,o,w; + + for(n=sz,o=0; n; n-=w,o+=w) { + if((w = PR_Write(fd, &buf[o], n)) < 0) + return IO_ERROR; + } + return IO_OKAY; +} + +/* ---------------------------- Standard UNIX ----------------------------- */ + +#ifdef XP_UNIX + +#include <sys/file.h> /* flock */ + +NSAPI_PUBLIC int system_fwrite_atomic(SYS_FILE fd, char *buf, int sz) +{ + int ret; +#if 0 + if(flock(fd,LOCK_EX) == -1) + return IO_ERROR; +#endif + ret = system_fwrite(fd,buf,sz); +#if 0 + if(flock(fd,LOCK_UN) == -1) + return IO_ERROR; /* ??? */ +#endif + return ret; +} + +/* -------------------------- system_nocoredumps -------------------------- */ + + +NSAPI_PUBLIC int system_nocoredumps(void) +{ +#ifdef BSD_RLIMIT + struct rlimit rl; + + rl.rlim_cur = 0; + rl.rlim_max = 0; + return setrlimit(RLIMIT_CORE, &rl); +#else +#if defined(SNI) +/* C++ compiler seems to find more that one overloaded instance of exit() ?! */ +#define EXITFUNC ::exit +#else +#define EXITFUNC exit +#endif + signal(SIGQUIT, EXITFUNC); + signal(SIGILL, EXITFUNC); + signal(SIGTRAP, EXITFUNC); + signal(SIGABRT, EXITFUNC); + signal(SIGIOT, EXITFUNC); + signal(SIGEMT, EXITFUNC); + signal(SIGFPE, EXITFUNC); + signal(SIGBUS, EXITFUNC); + signal(SIGSEGV, EXITFUNC); + signal(SIGSYS, EXITFUNC); + + + return 0; +#endif +} +#endif /* XP_UNIX */ + +/* --------------------------- file_setinherit ---------------------------- */ + +NSAPI_PUBLIC int file_setinherit(SYS_FILE fd, int value) +{ +#if defined(XP_WIN32) + int ret; + +// ret = SetHandleInformation((HANDLE)PR_FileDesc2NativeHandle(fd), 0, value?HANDLE_FLAG_INHERIT:0); + // This function did nothing before since the mask was set to 0. + ret = SetHandleInformation((HANDLE)PR_FileDesc2NativeHandle(fd), HANDLE_FLAG_INHERIT, value?HANDLE_FLAG_INHERIT:0); + return ret==0?-1:0; +#elif defined(XP_UNIX) + int flags = 0; + PRInt32 nativeFD; + PRFileDesc *bottom = fd; + + while (bottom->lower != NULL) { + bottom = bottom->lower; + } + + nativeFD = PR_FileDesc2NativeHandle(bottom); +#if 0 +fprintf(stderr, "\nInfo(file_setinherit): Native file descriptor is %d\n", nativeFD); +#endif + flags = fcntl(nativeFD, F_GETFD, 0); + if(flags == -1) + return -1; + if(value) + flags &= (~FD_CLOEXEC); + else + flags |= FD_CLOEXEC; + fcntl(nativeFD, F_SETFD, flags); + return 0; + + /* Comment out for ns security/ nspr integration (HACK for NOW) + int flags = fcntl(PR_FileDesc2NativeHandle(fd), F_GETFD, 0); + if(flags == -1) + return -1; + if(value) + flags &= (~FD_CLOEXEC); + else + flags |= FD_CLOEXEC; + fcntl(PR_FileDesc2NativeHandle(fd), F_SETFD, flags); + return 0; + */ +#endif +} + +NSAPI_PUBLIC SYS_FILE system_fopenRO(char *p) +{ + SYS_FILE f = PR_Open(p, PR_RDONLY, 0); + + if (!f) + return SYS_ERROR_FD; + return f; +} + +NSAPI_PUBLIC SYS_FILE system_fopenWA(char *p) +{ + SYS_FILE f = PR_Open(p, PR_RDWR|PR_CREATE_FILE|PR_APPEND, 0644); + + if (!f) + return SYS_ERROR_FD; + return f; +} + +NSAPI_PUBLIC SYS_FILE system_fopenRW(char *p) +{ + SYS_FILE f = PR_Open(p, PR_RDWR|PR_CREATE_FILE, 0644); + + if (!f) + return SYS_ERROR_FD; + return f; +} + +NSAPI_PUBLIC SYS_FILE system_fopenWT(char *p) +{ + SYS_FILE f = PR_Open(p, PR_RDWR|PR_CREATE_FILE|PR_TRUNCATE, 0644); + + if (!f) + return SYS_ERROR_FD; + return f; +} + +NSAPI_PUBLIC int system_fclose(SYS_FILE fd) +{ + return (PR_Close(fd)); +} + + +#ifdef FILE_WIN32 + +int CgiBuffering; + +NSAPI_PUBLIC SYS_FILE system_fopen(char *path, int access, int flags) +{ + char p2[MAX_PATH]; + SYS_FILE ret; + HANDLE fd; + + if (strlen(path) >= MAX_PATH) { + return SYS_ERROR_FD; + } + + file_unix2local(path, p2); + + fd = CreateFile(p2, access, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, flags, 0, NULL); + ret = PR_ImportFile((int32)fd); + + if(ret == INVALID_HANDLE_VALUE) + return SYS_ERROR_FD; + + return ret; +} + + + +NSAPI_PUBLIC int system_pread(SYS_FILE fd, char *buf, int BytesToRead) { + unsigned long BytesRead = 0; + int result = 0; + BOOLEAN TimeoutSet = FALSE; + + /* XXXMB - nspr20 should be able to do this; but right now it doesn't + * return proper error info. + * fix it later... + */ + if(ReadFile((HANDLE)PR_FileDesc2NativeHandle(fd), (LPVOID)buf, BytesToRead, &BytesRead, NULL) == FALSE) { + if (GetLastError() == ERROR_BROKEN_PIPE) { + return IO_EOF; + } else { + return IO_ERROR; + } + } + return (BytesRead ? BytesRead : IO_EOF); +} + +NSAPI_PUBLIC int system_pwrite(SYS_FILE fd, char *buf, int BytesToWrite) +{ + unsigned long BytesWritten; + + if (WriteFile((HANDLE)PR_FileDesc2NativeHandle(fd), (LPVOID)buf, + BytesToWrite, &BytesWritten, NULL) == FALSE) { + return IO_ERROR; + } + return BytesWritten; +} + + +NSAPI_PUBLIC int system_fwrite_atomic(SYS_FILE fd, char *buf, int sz) +{ + int ret; + +#if 0 + if(system_flock(fd) == IO_ERROR) + return IO_ERROR; +#endif + /* XXXMB - this is technically thread unsafe, but it catches any + * callers of fwrite_atomic when we're single threaded and just coming + * to life. + */ + if (!_atomic_write_lock) { + _atomic_write_lock = PR_NewLock(); + } + PR_Lock(_atomic_write_lock); + ret = system_fwrite(fd,buf,sz); + PR_Unlock(_atomic_write_lock); +#if 0 + if(system_ulock(fd) == IO_ERROR) + return IO_ERROR; +#endif + return ret; +} + + +NSAPI_PUBLIC void file_unix2local(char *path, char *p2) +{ + /* Try to handle UNIX-style paths */ + if((!strchr(path, FILE_PATHSEP))) { + int x; + + for(x = 0; path[x]; x++) + p2[x] = (path[x] == '/' ? '\\' : path[x]); + p2[x] = '\0'; + } + else + strcpy(p2, path); +} + + +NSAPI_PUBLIC int system_nocoredumps(void) +{ + return 0; +} + +/* --------------------------- system_winerr ------------------------------ */ + + +#include <winsock.h> +#include <errno.h> +#include "util.h" + +NSAPI_PUBLIC char *system_winsockerr(void) +{ + int errn = WSAGetLastError(); + + return FindError(errn); +} + +NSAPI_PUBLIC char *system_winerr(void) +{ + int errn = GetLastError(); + + if (errn == 0) + errn = WSAGetLastError(); + return FindError(errn); +} + +/* ------------------------- Dir related stuff ---------------------------- */ + + +NSAPI_PUBLIC SYS_DIR dir_open(char *pathp) +{ + dir_s *ret = (dir_s *) MALLOC(sizeof(dir_s)); + char path[MAX_PATH]; + int l; + + if (strlen(pathp) >= MAX_PATH) { + return NULL; + } + + l = util_sprintf(path, "%s", pathp) - 1; + path[strlen(pathp)] = '\0'; + if(path[strlen(path) - 1] != FILE_PATHSEP) + strcpy (path + strlen(path), "\\*.*"); + else + util_sprintf(path, "%s*.*", path); + + ret->de.d_name = NULL; + if( (ret->dp = FindFirstFile(path, &ret->fdata)) != INVALID_HANDLE_VALUE) + return ret; + FREE(ret); + return NULL; +} + +NSAPI_PUBLIC SYS_DIRENT *dir_read(SYS_DIR ds) +{ + if(FindNextFile(ds->dp, &ds->fdata) == FALSE) + return NULL; + if(ds->de.d_name) + FREE(ds->de.d_name); + ds->de.d_name = STRDUP(ds->fdata.cFileName); + + return &ds->de; +} + +NSAPI_PUBLIC void dir_close(SYS_DIR ds) +{ + FindClose(ds->dp); + if(ds->de.d_name) + FREE(ds->de.d_name); + FREE(ds); +} + +#endif /* FILE_WIN32 */ + +NSAPI_PUBLIC int file_notfound(void) +{ +#ifdef FILE_WIN32 + int errn = PR_GetError(); + return (errn == PR_FILE_NOT_FOUND_ERROR); +#else + return (errno == ENOENT); +#endif +} + +NSAPI_PUBLIC int dir_create_all(char *dir) +{ + struct stat fi; + char *t; + +#ifdef XP_WIN32 + t = dir + 3; +#else /* XP_UNIX */ + t = dir + 1; +#endif + while(1) { + t = strchr(t, FILE_PATHSEP); + if(t) *t = '\0'; + if(stat(dir, &fi) == -1) { + if(dir_create(dir) == -1) + return -1; + } + if(t) *t++ = FILE_PATHSEP; + else break; + } + return 0; +} + + +#ifdef XP_UNIX +#if !defined(SNI) && !defined(LINUX) +extern char *sys_errlist[]; +#endif /* SNI */ +#endif + +#ifdef NET_SSL + +#define ERRMSG_SIZE 35 +#ifdef THREAD_ANY +static int errmsg_key = -1; +#include "systhr.h" +/* Removed for ns security integration +#include "xp_error.h" +*/ +#else +static char errmsg[ERRMSG_SIZE]; +#endif + +#include "util.h" + +static char *_errmsg_new(int code) +{ + char *ret; +#ifdef THREAD_ANY + if(!(ret = (char *) systhread_getdata(errmsg_key))) { + ret = (char *) PERM_MALLOC(256); + systhread_setdata(errmsg_key, (void *)ret); + } +#else + ret = errmsg; +#endif + util_snprintf(ret, ERRMSG_SIZE, "libsec code %d", code); +#ifndef MCC_BATMAN + PR_SetError(0,0); +#endif + return ret; +} +#endif + + +void system_errmsg_init(void) +{ + if (errmsg_key == -1) { +#if defined(THREAD_ANY) && defined(NET_SSL) + errmsg_key = systhread_newkey(); +#endif +#ifdef XP_WIN32 + HashNtErrors(); +#endif + if (!_atomic_write_lock) + _atomic_write_lock = PR_NewLock(); + } +} + +NSAPI_PUBLIC int system_errmsg_fn(char **buff, size_t maxlen) +{ + char static_error[128]; + char *lmsg = 0; /* Local message pointer */ + size_t msglen = 0; + int sys_error = 0; + PRErrorCode nscp_error; +#ifdef XP_WIN32 + LPTSTR sysmsg = 0; +#endif + + + /* Grab the OS error message */ +#ifdef XP_WIN32 + sys_error = GetLastError(); +#else + sys_error = errno; +#endif + nscp_error = PR_GetError(); + + /* If there is a NSPR error, but it is "unknown", try to get the OSError + * and use that instead. + */ + if (nscp_error == PR_UNKNOWN_ERROR) + errno = PR_GetOSError(); + + if (nscp_error != 0 && nscp_error != PR_UNKNOWN_ERROR){ + char *nscp_error_msg; + + nscp_error_msg = nscperror_lookup(nscp_error); + if(nscp_error_msg){ + PR_SetError(0, 0); + lmsg = nscp_error_msg; + } else { + util_snprintf(static_error, ERRMSG_SIZE, "unknown error %d", nscp_error); + lmsg = static_error; + } + } else { +#if defined(XP_WIN32) + msglen = FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + GetLastError(), + LOCALE_SYSTEM_DEFAULT, + (LPTSTR)&sysmsg, + 0, + 0); + if (msglen > 0) + lmsg = sysmsg; + else + lmsg = system_winerr(); + SetLastError(0); +#else +/* replaced +#if defined(SNI) || defined(LINUX) + / C++ platform has no definition for sys_errlist / + lmsg = strerror(errno); +#else + lmsg = sys_errlist[errno]; +#endif +with lmsg =strerror(errno);*/ + lmsg=strerror(errno); + errno = 0; +#endif + } + + /* At this point lmsg points to something. */ + msglen = strlen(lmsg); + + if (*buff == NULL) + *buff = STRDUP(lmsg); + else if (maxlen > msglen) + memcpy(*buff, lmsg, msglen+1); + else + msglen = 0; + +#ifdef XP_WIN32 + /* NT's FormatMessage() dynamically allocated the msg; free it */ + if (sysmsg) + LocalFree(sysmsg); +#endif + + return msglen; +} + +NSAPI_PUBLIC char * +system_errmsg(void) +{ + char *buff = 0; + + if (errmsg_key == -1) + return "unknown early startup error"; + + // rmaxwell - This is extremely lame. + // Allocate a buffer in thread local storage to + // hold the last error message. + // The whole error message facility is broken and should be + // updated to get error strings out of the code. + if(!(buff = (char *) systhread_getdata(errmsg_key))) { + buff = (char *) PERM_MALLOC(errbuf_size); + systhread_setdata(errmsg_key, (void *)buff); + } + system_errmsg_fn(&buff, errbuf_size); + if (buff == 0) + buff = "Could not retrieve system error message"; + return buff; +} + +NSAPI_PUBLIC int +system_rename(char *oldpath, char *newpath) +{ + return rename(oldpath, newpath); +} + +NSAPI_PUBLIC int +system_unlink(char *path) +{ + return PR_Delete(path)==PR_FAILURE?-1:0; +} + +NSAPI_PUBLIC int system_lseek(SYS_FILE fd, int off, int wh) +{ + switch (wh) { + case 0: + return PR_Seek(fd, off, PR_SEEK_SET); + break; + case 1: + return PR_Seek(fd, off, PR_SEEK_CUR); + break; + case 2: + return PR_Seek(fd, off, PR_SEEK_END); + break; + default: + return -1; + } +} + +NSAPI_PUBLIC int +system_tlock(SYS_FILE fd) +{ + return PR_TLockFile(fd); +} + +NSAPI_PUBLIC int +system_flock(SYS_FILE fd) +{ + return PR_LockFile(fd); +} + +NSAPI_PUBLIC int +system_ulock(SYS_FILE fd) +{ + return PR_UnlockFile(fd); +} diff --git a/lib/base/fsmutex.cpp b/lib/base/fsmutex.cpp new file mode 100644 index 00000000..06fe2403 --- /dev/null +++ b/lib/base/fsmutex.cpp @@ -0,0 +1,187 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * fsmutex: Mutexes that are filesystem-based so they're available from more + * than one process and address space + * + * Rob McCool + */ + +#include "base/fsmutex.h" +#ifdef THREAD_ANY +#include "base/crit.h" +#include "base/systhr.h" +#endif + +#include "base/util.h" +#ifdef XP_WIN32 +typedef HANDLE sys_fsmutex_t; +#endif + +#ifdef XP_UNIX +#include "base/file.h" +typedef SYS_FILE sys_fsmutex_t; +#endif + + +typedef struct { + sys_fsmutex_t mutex; + char *id; +#ifdef THREAD_ANY + CRITICAL crit; +#endif + int flags; +} fsmutex_s; + + + +/* ----------------------------- fsmutex_init ----------------------------- */ + + +#ifdef XP_UNIX +static int +_fsmutex_create(fsmutex_s *fsm, char *name, int number) +{ + char tn[256]; + SYS_FILE lfd; + int visible = (fsm->flags & FSMUTEX_VISIBLE ? 1 : 0); + + util_snprintf(tn, 256, "/tmp/%s.%d", name, number); + if(!visible) + unlink(tn); + if( (lfd = PR_Open(tn, PR_RDWR|PR_CREATE_FILE, 0644)) == NULL) + return -1; + + if(!visible) + unlink(tn); + else + fsm->id = PERM_STRDUP(tn); + fsm->mutex = lfd; + return 0; +} +#endif + +#ifdef XP_WIN32 +static int +_fsmutex_create(fsmutex_s *fsm, char *name, int number) +{ + char tn[256]; + util_snprintf(tn, sizeof(tn), "%s.%d", name, number); + + fsm->id = NULL; + fsm->mutex = CreateMutex(NULL, FALSE, + (fsm->flags & FSMUTEX_VISIBLE ? tn : NULL)); + return (fsm->mutex ? 0 : -1); +} +#endif + +NSAPI_PUBLIC FSMUTEX +fsmutex_init(char *name, int number, int flags) +{ + fsmutex_s *ret = (fsmutex_s *) PERM_MALLOC(sizeof(fsmutex_s)); + + ret->flags = flags; + if(_fsmutex_create(ret, name, number) == -1) { + PERM_FREE(ret); + return NULL; + } +#ifdef THREAD_ANY + if(flags & FSMUTEX_NEEDCRIT) + ret->crit = crit_init(); +#endif + return (FSMUTEX) ret; +} + +#ifdef XP_UNIX +NSAPI_PUBLIC void +fsmutex_setowner(FSMUTEX fsm, uid_t uid, gid_t gid) +{ + if(!geteuid()) + (void) chown( ((fsmutex_s *)fsm)->id, uid, gid); +} +#endif + + +/* -------------------------- fsmutex_terminate --------------------------- */ + + +#ifdef XP_UNIX +static void +_fsmutex_delete(fsmutex_s *fsm) +{ + if(fsm->flags & FSMUTEX_VISIBLE) + unlink(fsm->id); + PERM_FREE(fsm->id); + PR_Close(fsm->mutex); +} +#endif + +#ifdef XP_WIN32 +static void +_fsmutex_delete(fsmutex_s *fsm) +{ + CloseHandle(fsm->mutex); +} +#endif + +NSAPI_PUBLIC void +fsmutex_terminate(FSMUTEX id) +{ + fsmutex_s *fsm = (fsmutex_s *) id; + + _fsmutex_delete(fsm); +#ifdef THREAD_ANY + if(fsm->flags & FSMUTEX_NEEDCRIT) + crit_terminate(fsm->crit); +#endif + PERM_FREE(fsm); +} + + +/* ----------------------------- fsmutex_lock ----------------------------- */ + + +NSAPI_PUBLIC void +fsmutex_lock(FSMUTEX id) +{ + fsmutex_s *fsm = (fsmutex_s *) id; +#ifdef THREAD_ANY + if(fsm->flags & FSMUTEX_NEEDCRIT) + crit_enter(fsm->crit); +#endif +#ifdef XP_UNIX +#ifdef THREAD_NSPR_USER + /* Poll to avoid blocking. XXXrobm If errno is wrong this may go awry. */ + while(system_tlock(fsm->mutex) == -1) + systhread_sleep(1000); +#else + system_flock(fsm->mutex ); +#endif +#endif +#ifdef XP_WIN32 + WaitForSingleObject(fsm->mutex, INFINITE); +#endif +} + + +/* ---------------------------- fsmutex_unlock ---------------------------- */ + + +NSAPI_PUBLIC void +fsmutex_unlock(FSMUTEX id) +{ + fsmutex_s *fsm = (fsmutex_s *) id; +#ifdef XP_UNIX + system_ulock(fsm->mutex); +#endif +#ifdef XP_WIN32 + ReleaseMutex(fsm->mutex); +#endif +#ifdef THREAD_ANY + if(fsm->flags & FSMUTEX_NEEDCRIT) + crit_exit(fsm->crit); +#endif +} diff --git a/lib/base/lexer.cpp b/lib/base/lexer.cpp new file mode 100644 index 00000000..e521c51f --- /dev/null +++ b/lib/base/lexer.cpp @@ -0,0 +1,978 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +/* + * Description (lexer.c) + * + * This module provides functions to assist parsers in lexical + * analysis. The idea is to provide a slightly higher-level + * interface than that of ctype.h. + */ + +#include "netsite.h" +#include "base/nsassert.h" + +#include "lexer_pvt.h" +#include "base/lexer.h" + +/* + * Description (lex_class_check) + * + * This function checks whether a given character belongs to one or + * specified character classes. + * + * Arguments: + * + * chtab - character class table pointer + * code - character code to be tested + * cbits - bit mask of character classes + * + * Returns: + * + * The return value is zero if the code is not in any of the character + * classes. It is non-zero, if the code is in at least one of the + * classes. + */ +NSAPI_PUBLIC +int lex_class_check(void * chtab, char code, unsigned long cbits) +{ + LEXClassTab_t * lct; /* character class table pointer */ + unsigned char * bp; /* bit vector pointer */ + int rv = 0; /* return value */ + int i; /* loop index */ + + lct = (LEXClassTab_t *)chtab; + + bp = lct->lct_bv + code * lct->lct_bvbytes; + + for (i = 0; i < lct->lct_bvbytes; ++i) { + if (*bp++ & cbits) { + rv = 1; + break; + } + cbits >>= 8; + } + + return rv; +} + +/* + * Description (lex_class_create) + * + * This function creates a new character class table. A + * character class table is used to map a character code to a + * set of character classes. The mapping for a given character + * is expressed as a bit vector, where each bit indicates the + * membership of that character in one of the character classes. + * + * Arguments: + * + * classc - the number of character classes being defined + * classv - pointers to null-terminated strings containing + * the character codes in each character class + * pchtab - indicates where to store a returned handle for + * the character class table + * + * Returns: + * + * If successful, the return value is the number of character + * classes specified (classc), and a handle for the created table + * is returned through pchtab. + * + * Usage Notes: + * + * Null (\000) can never be in any character classes, since it + * marks the end of the classv[] strings. + * + * classv[] can included NULL pointers, in which case bits will be + * allocated for corresponding empty character classes. + */ +NSAPI_PUBLIC +int lex_class_create(int classc, char * classv[], void **pchtab) +{ + int ncodes = 128; /* number of character encodings */ + int bvbytes; /* bytes per bit vector */ + LEXClassTab_t * ct; /* class table pointer */ + unsigned char * bp; /* bit vector pointer */ + char * cp; /* class string pointer */ + int bitmask; /* class bit mask */ + int bnum; /* byte number in bit vector */ + int ci; /* character index */ + int i; /* class index */ + + /* Get number of bytes per bit vector */ + NS_ASSERT(classc > 0); + bvbytes = (classc + 7) >> 3; + + /* Allocate the character class table */ + ct = (LEXClassTab_t *)calloc(1, sizeof(LEXClassTab_t) + ncodes * bvbytes); + if (ct == NULL) { + + /* Error - insufficient memory */ + return LEXERR_MALLOC; + } + + /* Initialize the class table */ + ct->lct_classc = classc; + ct->lct_bvbytes = bvbytes; + ct->lct_bv = (unsigned char *)(ct + 1); + + /* Initialize the bit vectors */ + for (i = 0; i < classc; ++i) { + + cp = classv[i]; + if (cp != NULL) { + + bitmask = 1 << (i & 7); + bnum = i >> 7; + + while ((ci = *cp++) != 0) { + bp = ct->lct_bv + ci + bnum; + *bp |= bitmask; + } + } + } + + /* Return pointer to table */ + NS_ASSERT(pchtab != NULL); + *pchtab = (void *)ct; + + return classc; +} + +NSAPI_PUBLIC +void lex_class_destroy(void * chtab) +{ + FREE((void *)chtab); +} + +NSAPI_PUBLIC +LEXStream_t * lex_stream_create(LEXStreamGet_t strmget, void * strmid, + char * buf, int buflen) +{ + LEXStream_t * lst; /* stream structure pointer */ + + /* Allocate the stream structure */ + lst = (LEXStream_t *)MALLOC(sizeof(LEXStream_t)); + if (lst == NULL) { + /* Error - insufficient memory */ + return 0; + } + + lst->lst_strmid = strmid; + lst->lst_get = strmget; + + /* + * Allocate a buffer for the stream if there's a positive length + * but a NULL buffer pointer. + */ + if ((buflen > 0) && (buf == NULL)) { + + buf = (char *)MALLOC(buflen); + if (buf == NULL) { + FREE((void *)lst); + return 0; + } + + /* Also initialize the current position and residual length */ + lst->lst_cp = buf; + lst->lst_len = 0; + lst->lst_flags = LST_FREEBUF; + } + + lst->lst_buf = buf; + lst->lst_buflen = buflen; + + return lst; +} + +NSAPI_PUBLIC +void lex_stream_destroy(LEXStream_t * lst) +{ + if ((lst->lst_flags & LST_FREEBUF) && (lst->lst_buf != NULL)) { + FREE(lst->lst_buf); + } + FREE((void *)lst); +} + +/* + * Description (lex_token_new) + * + * This function creates a new token object. A token object is + * used to accumulate text in an associated buffer. If the + * 'growlen' argument is specified as a value that is greater + * than zero, then the token buffer will be reallocated as + * necessary to accomodate more text. The initial size of + * the token buffer is given by 'initlen', which may be zero, + * and should be zero if lex_token_setbuf() is used. + * + * The token object is allocated from the memory pool given + * by the 'pool' argument. The default pool for the current + * thread is used if 'pool' is null. + * + * Arguments: + * + * pool - handle for memory pool to be used + * initlen - initial length of token buffer + * growlen - amount to grow a full token buffer + * token - pointer to returned token handle + * + * Returns: + * + * If successful, the function return value is zero and a handle + * for the new token is returned via 'token'. Otherwise a negative + * error code is returned. + */ + +NSAPI_PUBLIC +int lex_token_new(pool_handle_t * pool, int initlen, int growlen, void **token) +{ + LEXToken_t * lt; /* new token pointer */ + + /* Allocate the token structure */ + if (pool) { + lt = (LEXToken_t *)pool_calloc(pool, 1, sizeof(LEXToken_t)); + } + else { + lt = (LEXToken_t *)CALLOC(sizeof(LEXToken_t)); + } + if (lt == NULL) { + /* Error - insufficient memory */ + return LEXERR_MALLOC; + } + + /* Save the memory pool handle for future allocations */ + lt->lt_mempool = pool; + + /* Allocate the initial token buffer if initlen > 0 */ + if (initlen > 0) { + if (pool) { + lt->lt_buf = (char *)pool_malloc(pool, initlen); + } + else { + lt->lt_buf = (char *)MALLOC(initlen); + } + if (lt->lt_buf == NULL) { + /* Error - insufficient memory */ + if (pool) { + pool_free(pool, (void *)lt); + } + else { + FREE((void *)lt); + } + return LEXERR_MALLOC; + } + + lt->lt_initlen = initlen; + lt->lt_buflen = initlen; + lt->lt_buf[0] = 0; + } + + if (growlen > 0) lt->lt_inclen = growlen; + + NS_ASSERT(token != NULL); + *token = (void *)lt; + + return 0; +} + +/* + * Description (lex_token_start) + * + * This function discards any current contents of the token buffer + * associated with a specified token object, so that any new data + * appended to the token will start at the beginning of the token + * buffer. If there is no token buffer currently associated with + * the token, and the 'initlen' value specified to lex_token_new() + * was greater than zero, then a new token buffer is allocated. + * This function enables a token and optionally its token buffer + * to be reused. + * + * Arguments: + * + * token - handle for token object + * + * Returns: + * + * If successful, the function return value is zero. Otherwise + * a negative error code is returned. + */ + +NSAPI_PUBLIC int +lex_token_start(void * token) +{ + LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */ + + /* Do we need to allocate a token buffer? */ + if ((lt->lt_buf == NULL) && (lt->lt_initlen > 0)) { + + /* Allocate the initial token buffer */ + if (lt->lt_mempool) { + lt->lt_buf = (char *)pool_malloc(lt->lt_mempool, lt->lt_initlen); + } + else { + lt->lt_buf = (char *)MALLOC(lt->lt_initlen); + } + if (lt->lt_buf == NULL) { + /* Error - insufficient memory */ + return LEXERR_MALLOC; + } + lt->lt_buflen = lt->lt_initlen; + } + + lt->lt_len = 0; + lt->lt_buf[0] = 0; + + return 0; +} + +/* + * Description (lex_token_info) + * + * This function returns information about the token buffer currently + * associated with a token object. This includes a pointer to the + * token data, if any, the current length of the token data, and the + * current size of the token buffer. + * + * Arguments: + * + * token - handle for token object + * tdatalen - pointer to returned token data length + * (may be null) + * tbufflen - pointer to returned token buffer length + * (may be null) + * + * Returns: + * + * The function return value is a pointer to the beginning of the + * token data, or null if there is no token buffer associated with + * the token. The token data length and token buffer length are + * returned via 'tdatalen' and 'tbufflen', respectively. + */ + +NSAPI_PUBLIC +char * lex_token_info(void * token, int * tdatalen, int * tbufflen) +{ + LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */ + + if (tdatalen) *tdatalen = lt->lt_len; + if (tbufflen) *tbufflen = lt->lt_buflen; + + return lt->lt_buf; +} + +/* + * Description (lex_token) + * + * This function returns a pointer to the current token buffer, if any. + * If the length of the token is also needed, use lex_token_info(). + * This function would normally be used when the token is a + * null-terminated string. See also lex_token_take(). + * + * Arguments: + * + * token - handle for token object + * + * Returns: + * + * A pointer to the beginning of the current token is returned. + * The pointer is null if no token buffer is currently associated + * with the token object. + */ + +NSAPI_PUBLIC +char * lex_token(void * token) +{ + LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */ + + return lt->lt_buf; +} + +/* + * Description (lex_token_destroy) + * + * This function destroys a specified token object. The memory + * associated with the token object and its token buffer, if any, + * is freed to whence it came. Note that token objects can be + * associated with a memory pool, and destroyed implicitly when + * the pool is destroyed via pool_destroy(). + * + * Arguments: + * + * token - handle for token object + */ + +NSAPI_PUBLIC +void lex_token_destroy(void * token) +{ + LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */ + + if (lt) { + if (lt->lt_mempool) { + if (lt->lt_buf) { + pool_free(lt->lt_mempool, (void *)(lt->lt_buf)); + } + pool_free(lt->lt_mempool, (void *)lt); + } + else { + if (lt->lt_buf) { + FREE(lt->lt_buf); + } + FREE(lt); + } + } +} + +/* + * Description (lex_token_get) + * + * This function returns a pointer to the current token buffer, + * leaving the token with no associated token buffer. The caller + * assumes ownership of the returned token buffer. The length + * of the token data and the length of the token buffer are returned + * if requested. Note that lex_token_take() performs a similar + * operation. + * + * Arguments: + * + * token - handle for token object + * tdatalen - pointer to returned token data length + * (may be null) + * tbufflen - pointer to returned token buffer length + * (may be null) + * + * Returns: + * + * The function return value is a pointer to the beginning of the + * token data, or null if there is no token buffer associated with + * the token. The token data length and token buffer length are + * returned via 'tdatalen' and 'tbufflen', respectively. + */ + +NSAPI_PUBLIC +char * lex_token_get(void * token, int * tdatalen, int * tbufflen) +{ + LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */ + char * tokenstr; + + tokenstr = lt->lt_buf; + if (tdatalen) *tdatalen = lt->lt_len; + if (tbufflen) *tbufflen = lt->lt_buflen; + + lt->lt_buf = NULL; + lt->lt_buflen = 0; + lt->lt_len = 0; + + return tokenstr; +} + +/* + * Description (lex_token_take) + * + * This function returns a pointer to the current token buffer, + * leaving the token with no associated token buffer. The caller + * assumes ownership of the returned token buffer. Note that + * lex_token_get() performs a similar operation, but returns more + * information. + * + * Arguments: + * + * token - handle for token object + * + * Returns: + * + * A pointer to the beginning of the current token is returned. + * The pointer is null if no token buffer is currently associated + * with the token object. + */ + +NSAPI_PUBLIC +char * lex_token_take(void * token) +{ + LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */ + char * tokenstr; + + tokenstr = lt->lt_buf; + + lt->lt_buf = NULL; + lt->lt_buflen = 0; + lt->lt_len = 0; + + return tokenstr; +} + +/* + * Description (lex_token_append) + * + * This function appends data to the end of a token. If 'growlen' + * was specified as a greater-than-zero value for lex_token_new(), + * then the token buffer may be reallocated to accomodate the + * new data if necessary. A null byte is maintained in the token + * buffer following the token data, but it is not included in the + * token data length. + * + * Arguments: + * + * token - handle for token object + * nbytes - number of bytes of new data + * src - pointer to new data + * + * Returns: + * + * If successful, the function return value is the new length of + * the token data. Otherwise a negative error code is returned. + */ + +NSAPI_PUBLIC +int lex_token_append(void * token, int nbytes, char * src) +{ + LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */ + int bufsize; + int length; + + NS_ASSERT(nbytes >= 0); + NS_ASSERT((src != NULL) || (nbytes == 0)); + + if (nbytes > 0) { + + bufsize = lt->lt_buflen; + length = lt->lt_len + nbytes; + + if (length >= bufsize) { + + while (length >= bufsize) { + bufsize += lt->lt_inclen; + } + + if (lt->lt_mempool) { + if (lt->lt_buf) { + lt->lt_buf = (char *)pool_realloc(lt->lt_mempool, + lt->lt_buf, bufsize); + } + else { + lt->lt_buf = (char *)pool_malloc(lt->lt_mempool, bufsize); + } + } + else { + if (lt->lt_buf) { + lt->lt_buf = (char *)REALLOC(lt->lt_buf, bufsize); + } + else { + lt->lt_buf = (char *)MALLOC(bufsize); + } + } + } + + if (lt->lt_buf) { + + memcpy((void *)(lt->lt_buf + lt->lt_len), (void *)src, nbytes); + lt->lt_buf[length] = 0; + lt->lt_len = length; + lt->lt_buflen = bufsize; + } + else { + /* Error - insufficient memory */ + return LEXERR_MALLOC; + } + } + + return lt->lt_len; +} + +NSAPI_PUBLIC +int lex_next_char(LEXStream_t * lst, void * chtab, unsigned long cbits) +{ + LEXClassTab_t * lct; /* character class table pointer */ + unsigned char * bp; /* bit vector pointer */ + unsigned long bitmask; /* class bit mask temporary */ + int rv; /* return value */ + int i; /* loop index */ + + lct = (LEXClassTab_t *)chtab; + + /* Go get more stream data if none left in the buffer */ + if (lst->lst_len <= 0) { + rv = (*lst->lst_get)(lst); + if (rv <= 0) { + return rv; + } + } + + /* Get the next character from the buffer */ + rv = *lst->lst_cp; + + bitmask = cbits; + bp = lct->lct_bv + rv * lct->lct_bvbytes; + + for (i = 0; i < lct->lct_bvbytes; ++i) { + if (*bp++ & bitmask) { + /* Update the buffer pointer and length */ + lst->lst_cp += 1; + lst->lst_len -= 1; + break; + } + bitmask >>= 8; + } + + return rv; +} + +NSAPI_PUBLIC +int lex_scan_over(LEXStream_t * lst, void * chtab, unsigned long cbits, + void * token) +{ + LEXClassTab_t * lct; /* character class table pointer */ + char * cp; /* current pointer in stream buffer */ + unsigned char * bp; /* bit vector pointer */ + unsigned long bitmask; /* class bit mask temporary */ + int cv = 0; /* current character value */ + int rv = 0; /* return value */ + int slen; /* token segment length */ + int done = 0; /* done indication */ + int i; /* loop index */ + + lct = (LEXClassTab_t *)chtab; + + while (!done) { + + /* Go get more stream data if none left in the buffer */ + if (lst->lst_len <= 0) { + rv = (*lst->lst_get)(lst); + if (rv <= 0) { + return rv; + } + } + + slen = 0; + cp = lst->lst_cp; + + while (slen < lst->lst_len) { + cv = *cp; + bitmask = cbits; + bp = lct->lct_bv + cv * lct->lct_bvbytes; + for (i = 0; i < lct->lct_bvbytes; ++i) { + if (*bp++ & bitmask) goto more_token; + bitmask >>= 8; + } + + done = 1; + break; + + more_token: + slen += 1; + cp += 1; + } + + /* If the current segment is not empty, append it to the token */ + if (slen > 0) { + rv = lex_token_append(token, slen, lst->lst_cp); + if (rv < 0) break; + + /* Update the stream buffer pointer and length */ + lst->lst_cp += slen; + lst->lst_len -= slen; + } + } + + return ((rv < 0) ? rv : cv); +} + +/* + * Description (lex_scan_string) + * + * This function parses a quoted string into the specified token. + * The current character in the LEX stream is taken to be the + * beginning quote character. The quote character may be included + * in the string by preceding it with a '\'. Any newline + * characters to be included in the string must also be preceded + * by '\'. The string is terminated by another occurrence of the + * quote character, or an unquoted newline, or EOF. + * + * Arguments: + * + * lst - pointer to LEX stream structure + * token - handle for token + * flags - bit flags (unused - must be zero) + * + * Returns: + * + * The terminating character is returned, or zero if EOF. The + * string is returned in the token, without the beginning and + * ending quote characters. An error is indicated by a negative + * return value. + */ + +NSAPI_PUBLIC +int lex_scan_string(LEXStream_t * lst, void * token, int flags) +{ + char * cp; /* current pointer in stream buffer */ + int cv; /* current character value */ + int rv; /* return value */ + int slen; /* token segment length */ + int done = 0; /* done indication */ + int cquote = 0; /* character quote indication */ + int qchar = -1; /* quote character */ + + while (!done) { + + /* Go get more stream data if none left in the buffer */ + if (lst->lst_len <= 0) { + rv = (*lst->lst_get)(lst); + if (rv <= 0) { + return rv; + } + } + + slen = 0; + cp = lst->lst_cp; + + while (slen < lst->lst_len) { + + /* Get the next character */ + cv = *cp; + + /* Pick up the quote character if we don't have it yet */ + if (qchar < 0) { + qchar = cv; + + /* Don't include it in the string */ + lst->lst_cp += 1; + lst->lst_len -= 1; + cp += 1; + continue; + } + + /* cquote is 1 if the last character was '\' */ + if (cquote == 0) { + + /* Is this a string terminator? */ + if ((cv == qchar) || (cv == '\n')) { + + /* Append whatever we have to this point */ + if (slen > 0) goto append_it; + + /* + * If the terminator is the expected quote character, + * just skip it. If it's anything else, leave it as + * the current character. + */ + if (cv == qchar) { + lst->lst_cp += 1; + lst->lst_len -= 1; + } + + done = 1; + goto append_it; + } + + /* Got the character quote character? */ + if (cv == '\\') { + + /* Append anything we have so far first */ + if (slen > 0) goto append_it; + + /* Then skip the character */ + cquote = 1; + lst->lst_cp += 1; + lst->lst_len -= 1; + cp += 1; + continue; + } + } + else { + + /* Include any character following '\' */ + cquote = 0; + } + + /* Include this character in the string */ + slen += 1; + cp += 1; + } + + append_it: + + /* If the current segment is not empty, append it to the token */ + if (slen > 0) { + rv = lex_token_append(token, slen, lst->lst_cp); + if (rv < 0) break; + + /* Update the stream buffer pointer and length */ + lst->lst_cp += slen; + lst->lst_len -= slen; + } + } + + return ((rv < 0) ? rv : cv); +} + +NSAPI_PUBLIC +int lex_scan_to(LEXStream_t * lst, void * chtab, unsigned long cbits, + void * token) +{ + LEXClassTab_t * lct; /* character class table pointer */ + unsigned char * bp; /* bit vector pointer */ + char * cp; /* current pointer in stream buffer */ + unsigned long bitmask; /* class bit mask temporary */ + int cv = 0; /* current character value */ + int rv = 0; /* return value */ + int slen; /* token segment length */ + int done = 0; /* done indication */ + int i; /* loop index */ + + lct = (LEXClassTab_t *)chtab; + + while (!done) { + + /* Go get more stream data if none left in the buffer */ + if (lst->lst_len <= 0) { + rv = (*lst->lst_get)(lst); + if (rv <= 0) { + return rv; + } + } + + slen = 0; + cp = lst->lst_cp; + + while (slen < lst->lst_len) { + cv = *cp; + bitmask = cbits; + bp = lct->lct_bv + cv * lct->lct_bvbytes; + for (i = 0; i < lct->lct_bvbytes; ++i) { + if (*bp++ & bitmask) { + done = 1; + goto append_it; + } + bitmask >>= 8; + } + + slen += 1; + cp += 1; + } + + append_it: + + /* If the current segment is not empty, append it to the token */ + if (slen > 0) { + rv = lex_token_append(token, slen, lst->lst_cp); + if (rv < 0) break; + + /* Update the stream buffer pointer and length */ + lst->lst_cp += slen; + lst->lst_len -= slen; + } + } + + return ((rv < 0) ? rv : cv); +} + +NSAPI_PUBLIC +int lex_skip_over(LEXStream_t * lst, void * chtab, unsigned long cbits) +{ + LEXClassTab_t * lct; /* character class table pointer */ + unsigned char * bp; /* bit vector pointer */ + char * cp; /* current pointer in stream buffer */ + unsigned long bitmask; /* class bit mask temporary */ + int rv = 0; /* return value */ + int slen; /* token segment length */ + int done = 0; /* done indication */ + int i; /* loop index */ + + lct = (LEXClassTab_t *)chtab; + + while (!done) { + + /* Go get more stream data if none left in the buffer */ + if (lst->lst_len <= 0) { + rv = (*lst->lst_get)(lst); + if (rv <= 0) { + return rv; + } + } + + slen = 0; + cp = lst->lst_cp; + + while (slen < lst->lst_len) { + rv = *cp; + bitmask = cbits; + bp = lct->lct_bv + rv * lct->lct_bvbytes; + for (i = 0; i < lct->lct_bvbytes; ++i) { + if (*bp++ & bitmask) goto next_ch; + bitmask >>= 8; + } + + done = 1; + break; + + next_ch: + slen += 1; + cp += 1; + } + + if (slen > 0) { + /* Update the stream buffer pointer and length */ + lst->lst_cp += slen; + lst->lst_len -= slen; + } + } + + return rv; +} + +NSAPI_PUBLIC +int lex_skip_to(LEXStream_t * lst, void * chtab, unsigned long cbits) +{ + LEXClassTab_t * lct; /* character class table pointer */ + unsigned char * bp; /* bit vector pointer */ + char * cp; /* current pointer in stream buffer */ + unsigned long bitmask; /* class bit mask temporary */ + int rv; /* return value */ + int slen; /* token segment length */ + int done = 0; /* done indication */ + int i; /* loop index */ + + lct = (LEXClassTab_t *)chtab; + + while (!done) { + + /* Go get more stream data if none left in the buffer */ + if (lst->lst_len <= 0) { + rv = (*lst->lst_get)(lst); + if (rv <= 0) { + return rv; + } + } + + slen = 0; + cp = lst->lst_cp; + + while (slen < lst->lst_len) { + rv = *cp; + bitmask = cbits; + bp = lct->lct_bv + rv * lct->lct_bvbytes; + for (i = 0; i < lct->lct_bvbytes; ++i) { + if (*bp++ & bitmask) { + done = 1; + goto update_it; + } + bitmask >>= 8; + } + slen += 1; + cp += 1; + } + + update_it: + /* Update the stream buffer pointer and length */ + if (slen > 0) { + lst->lst_cp += slen; + lst->lst_len -= slen; + } + } + + return rv; +} diff --git a/lib/base/lexer_pvt.h b/lib/base/lexer_pvt.h new file mode 100644 index 00000000..d4a43f38 --- /dev/null +++ b/lib/base/lexer_pvt.h @@ -0,0 +1,30 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +#ifndef __LEXER_PVT_H +#define __LEXER_PVT_H + +#ifndef _POOL_H_ +#include "base/pool.h" +#endif /* _POOL_H_ */ + +typedef struct LEXClassTab_s LEXClassTab_t; +struct LEXClassTab_s { + int lct_classc; /* number of character classes */ + int lct_bvbytes; /* number of bytes per bit vector */ + unsigned char * lct_bv; /* pointer to bit vector area */ +}; + +typedef struct LEXToken_s LEXToken_t; +struct LEXToken_s { + char * lt_buf; /* token buffer pointer */ + int lt_len; /* length of token data */ + int lt_buflen; /* current length of buffer */ + int lt_inclen; /* buffer length increment */ + int lt_initlen; /* initial length of token buffer */ + pool_handle_t * lt_mempool; /* token memory pool */ +}; + +#endif /* __LEXER_PVT_H */ diff --git a/lib/base/net.cpp b/lib/base/net.cpp new file mode 100644 index 00000000..0d15b121 --- /dev/null +++ b/lib/base/net.cpp @@ -0,0 +1,578 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * net.c: sockets abstraction and DNS related things + * + * Note: sockets created with net_socket are placed in non-blocking mode, + * however this API simulates that the calls are blocking. + * + * Rob McCool + */ + + +#include "netsite.h" +#include "prio.h" +#include "private/pprio.h" +#include <nspr.h> + +#include <frame/conf.h> +/* Removed for ns security integration +#include "sslio/sslio.h" +*/ + +#include "net.h" +#include "util.h" +#include "daemon.h" /* child_exit */ +#include "ereport.h" /* error reporting */ +#include <string.h> +#ifdef XP_UNIX +#include <arpa/inet.h> /* inet_ntoa */ +#include <netdb.h> /* hostent stuff */ +#ifdef NEED_GHN_PROTO +extern "C" int gethostname (char *name, size_t namelen); +#endif +#endif /* XP_UNIX */ +#ifdef LINUX +#include <sys/ioctl.h> /* ioctl */ +#endif + +extern "C" { +#include "ssl.h" +} + +#if defined(OSF1) +#include <stropts.h> +#endif +#include "base/systems.h" +#include "base/dbtbase.h" + +#if defined(OSF1) +#include <stropts.h> +#endif + +#ifdef IRIX +#include <bstring.h> /* fd_zero uses bzero */ +#endif +#include "netio.h" + +net_io_t net_io_functions; +/* removed for ns security integration +#include "xp_error.h" +*/ + +#include "libadmin/libadmin.h" + +int net_enabledns = 1; +int net_enableAsyncDNS = 0; +int net_listenqsize = DAEMON_LISTEN_SIZE; +unsigned int NET_BUFFERSIZE = NET_DEFAULT_BUFFERSIZE; +unsigned int NET_READ_TIMEOUT = NET_DEFAULT_READ_TIMEOUT; +unsigned int NET_WRITE_TIMEOUT = NET_DEFAULT_WRITE_TIMEOUT; +unsigned int SSL_HANDSHAKE_TIMEOUT = SSL_DEFAULT_HANDSHAKE_TIMEOUT; + + +/* ------------------------------ net_init -------------------------------- */ +NSAPI_PUBLIC int net_init(int security_on) +{ + return 0; +} + +/* ------------------------------ net_socket ------------------------------ */ +NSAPI_PUBLIC SYS_NETFD net_socket(int domain, int type, int protocol) +{ + SYS_NETFD sock; + SYS_NETFD prsock; + + if (security_active) { + if (protocol == IPPROTO_TCP) + prsock = PR_NewTCPSocket(); + else + prsock = PR_NewUDPSocket(); + if(prsock) + sock = SSL_ImportFD(NULL, prsock); + else sock = NULL; + } + else { + if (protocol == IPPROTO_TCP) sock = PR_NewTCPSocket(); + else sock = PR_NewUDPSocket(); + } + + if (sock == NULL) + return (SYS_NETFD)SYS_NET_ERRORFD; + return sock; +} + + +/* ---------------------------- net_getsockopt ---------------------------- */ +NSAPI_PUBLIC int net_getsockopt(SYS_NETFD s, int level, int optname, + void *optval, int *optlen) +{ + return getsockopt(PR_FileDesc2NativeHandle(s), level, optname, + (char *)optval, (TCPLEN_T *)optlen); +} + + +/* ---------------------------- net_setsockopt ---------------------------- */ + + +NSAPI_PUBLIC int net_setsockopt(SYS_NETFD s, int level, int optname, + const void *optval, int optlen) +{ + return setsockopt(PR_FileDesc2NativeHandle(s), level, optname, + (const char *)optval, optlen); +} +/* ------------------------------ net_listen ------------------------------ */ + + +NSAPI_PUBLIC int net_listen(SYS_NETFD s, int backlog) +{ + return PR_Listen(s, backlog)==PR_FAILURE?IO_ERROR:0; +} + + +/* ------------------------- net_create_listener -------------------------- */ + + +NSAPI_PUBLIC SYS_NETFD net_create_listener(char *ipstr, int port) +{ + SYS_NETFD sd; + /* + struct sockaddr_in sa_server; + */ + PRNetAddr sa_server; + PRStatus status; + PRInt32 flags; + + if ((sd = net_socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == SYS_NET_ERRORFD) { + return SYS_NET_ERRORFD; + } + +#ifdef SOLARIS + /* + * unset NONBLOCK flag; + */ + /* Have no idea why Solaris want to unset NONBLOCK flag when it should + be in NON-BLOCK mode, and new NSPR20 does not give file descriptor + back, so the code are removed --- yjh + flags = fcntl(sd->osfd, F_GETFL, 0); + fcntl(sd->osfd, F_SETFL, flags & ~O_NONBLOCK); + */ +#endif + /* Convert to NSPR21 for ns security integration + ZERO((char *) &sa_server, sizeof(sa_server)); + sa_server.sin_family=AF_INET; + sa_server.sin_addr.s_addr = (ipstr ? inet_addr(ipstr) : htonl(INADDR_ANY)); + sa_server.sin_port=htons(port); + if(net_bind(sd, (struct sockaddr *) &sa_server,sizeof(sa_server)) < 0) { + return SYS_NET_ERRORFD; + } + net_listen(sd, net_listenqsize); + */ + + if (ipstr) { + status = PR_InitializeNetAddr(PR_IpAddrNull, port, &sa_server); + if (status == PR_SUCCESS) sa_server.inet.ip = inet_addr(ipstr); + else return SYS_NET_ERRORFD; + } + else { + status = PR_InitializeNetAddr(PR_IpAddrAny, port, &sa_server); + if (status == PR_FAILURE) return SYS_NET_ERRORFD; + } + + status = PR_Bind(sd, &sa_server); + if (status == PR_FAILURE) return SYS_NET_ERRORFD; + + + status = PR_Listen(sd, net_listenqsize); + if (status == PR_FAILURE) return SYS_NET_ERRORFD; + + return sd; +} +/* ------------------------------ net_select ------------------------------ */ + +/* +NSAPI_PUBLIC int net_select(int nfds, fd_set *r, fd_set *w, fd_set *e, + struct timeval *timeout) +{ + PR_fd_set rd, wr, ex; + int index; + int rv; + + if (nfds > (64*1024)) + return -1; + + PR_FD_ZERO(&rd); + PR_FD_ZERO(&wr); + PR_FD_ZERO(&ex); + + for (index=0; index<nfds; index++) { + if (FD_ISSET(index, r)) + PR_FD_NSET(index, &rd); + if (FD_ISSET(index, w)) + PR_FD_NSET(index, &wr); + if (FD_ISSET(index, e)) + PR_FD_NSET(index, &ex); + } + + rv = PR_Select(0, &rd, &wr, &ex, PR_SecondsToInterval(timeout->tv_sec)); + if (rv > 0) { + FD_ZERO(r); + FD_ZERO(w); + FD_ZERO(e); + for (index=0; index<nfds; index++) { + if (PR_FD_NISSET(index, &rd)) + FD_SET(index, r); + if (PR_FD_NISSET(index, &wr)) + FD_SET(index, w); + if (PR_FD_NISSET(index, &ex)) + FD_SET(index, e); + } + } + + return rv; +} +*/ + +NSAPI_PUBLIC int net_select(int nfds, fd_set *r, fd_set *w, fd_set *e, + struct timeval *timeout) +{ + return 1; +} + + +/* ----------------------------- net_isalive ------------------------------ */ + + +/* + * XXXmikep As suggested by shaver@ingenia.com. If everyone was POSIX + * compilent, a write() of 0 bytes would work as well + */ +NSAPI_PUBLIC int net_isalive(SYS_NETFD sd) +{ + char c; + if (PR_RecvFrom(sd, &c, 1, MSG_PEEK, NULL, 0) == -1 ) { + return 0; + } + return 1; +} + + +/* ------------------------------ net_connect ------------------------------ */ + +NSAPI_PUBLIC int net_connect(SYS_NETFD s, const void *sockaddr, int namelen) +{ + int rv; + + child_status(CHILD_WRITING); + rv = PR_Connect(s, (PRNetAddr *)sockaddr, PR_INTERVAL_NO_TIMEOUT); + child_status(CHILD_PROCESSING); + + return rv==PR_FAILURE?IO_ERROR:0; +} + + +/* ------------------------------ net_ioctl ------------------------------ */ + + +NSAPI_PUBLIC int net_ioctl(SYS_NETFD s, int tag, void *result) +{ +#if defined(NET_WINSOCK) + return ioctlsocket(PR_FileDesc2NativeHandle(s),tag,(unsigned long *)result); +#elif defined(XP_UNIX) + return ioctl(PR_FileDesc2NativeHandle(s), tag, result); +#else + write me; +#endif + +} +/* --------------------------- net_getpeername ---------------------------- */ + + +NSAPI_PUBLIC int net_getpeername(SYS_NETFD s, struct sockaddr *name, + int *namelen) +{ +#if defined (SNI) || defined (UnixWare) + return getpeername(PR_FileDesc2NativeHandle(s), name, (size_t *)namelen); +#else /* defined (SNI) || defined (UnixWare) */ + return getpeername(PR_FileDesc2NativeHandle(s), name, (TCPLEN_T *)namelen); +#endif /* defined (SNI) || defined (UnixWare) */ +} + + +/* ------------------------------ net_close ------------------------------- */ + + +NSAPI_PUBLIC int net_close(SYS_NETFD s) +{ + return PR_Close(s)==PR_FAILURE?IO_ERROR:0; +} + +NSAPI_PUBLIC int net_shutdown(SYS_NETFD s, int how) +{ + switch (how) { + case 0: + return PR_Shutdown(s, PR_SHUTDOWN_RCV); + break; + case 1: + return PR_Shutdown(s, PR_SHUTDOWN_SEND); + break; + case 2: + return PR_Shutdown(s, PR_SHUTDOWN_BOTH); + break; + default: + return -1; + } + + return 0; +} + + + +/* ------------------------------- net_bind ------------------------------- */ + +NSAPI_PUBLIC int net_bind(SYS_NETFD s, const struct sockaddr *name, + int namelen) +{ + return PR_Bind(s, (const PRNetAddr *)name)==PR_FAILURE?IO_ERROR:0; +} + + +/* ------------------------------ net_accept ------------------------------ */ + + +NSAPI_PUBLIC SYS_NETFD net_accept(SYS_NETFD sd, struct sockaddr *addr, + int *addrlen) +{ + SYS_NETFD sock = PR_Accept(sd, (PRNetAddr *)addr, PR_INTERVAL_NO_TIMEOUT); + + if (sock == NULL) + return SYS_NET_ERRORFD; + return sock; +} + +/* ------------------------------- net_read ------------------------------- */ + +NSAPI_PUBLIC int net_read(SYS_NETFD fd, char *buf, int sz, int timeout) +{ + int rv; + + if (timeout == NET_ZERO_TIMEOUT) + timeout = PR_INTERVAL_NO_WAIT; + else if (timeout == NET_INFINITE_TIMEOUT) + timeout = PR_INTERVAL_NO_TIMEOUT; + else + timeout = PR_SecondsToInterval(timeout); + + child_status(CHILD_READING); + rv = PR_Recv(fd, buf, sz, 0, timeout); + + child_status(CHILD_PROCESSING); + return rv; +} + + +/* ------------------------------ net_write ------------------------------- */ + +#ifndef NEEDS_WRITEV +int net_writev(SYS_NETFD fd, struct iovec *iov, int iov_size) +{ + int rv; + + child_status(CHILD_WRITING); + rv = PR_Writev(fd, (PRIOVec *)iov, iov_size, PR_INTERVAL_NO_TIMEOUT); + child_status(CHILD_PROCESSING); + return rv; +} + +#else /* NEEDS_WRITEV */ + +/* Since SSL and NT do not support writev(), we just emulate it. + * This does not lead to the optimal number of packets going out... + */ +int net_writev(SYS_NETFD fd, struct iovec *iov, int iov_size) +{ + int index; + + child_status(CHILD_WRITING); + + for (index=0; index<iov_size; index++) { + + /* net_write already does the buffer for nonblocked IO */ + if ( net_write(fd, iov[index].iov_base, iov[index].iov_len) ==IO_ERROR){ + child_status(CHILD_PROCESSING); + return IO_ERROR; + } + } + + child_status(CHILD_PROCESSING); + return IO_OKAY; +} +#endif /* NEEDS_WRITEV */ + + +NSAPI_PUBLIC int net_write(SYS_NETFD fd, char *buf, int sz) +{ + int rv; + + child_status(CHILD_WRITING); + rv = PR_Send(fd, buf, sz, 0, PR_INTERVAL_NO_TIMEOUT); + child_status(CHILD_PROCESSING); + if(rv < 0) { + return IO_ERROR; + } + return rv; +} + +NSAPI_PUBLIC int net_socketpair(SYS_NETFD *pair) +{ + return PR_NewTCPSocketPair(pair); +} + +#ifdef XP_UNIX +NSAPI_PUBLIC SYS_NETFD net_dup2(SYS_NETFD prfd, int osfd) +{ + SYS_NETFD newfd = NULL; + + if (prfd && PR_FileDesc2NativeHandle(prfd) != osfd) { + if (dup2(PR_FileDesc2NativeHandle(prfd), osfd) != -1) { + newfd = PR_ImportFile(osfd); + if (!newfd) + close(osfd); + } + } + + return newfd; +} + +NSAPI_PUBLIC int net_is_STDOUT(SYS_NETFD prfd) +{ + int fd = PR_FileDesc2NativeHandle(prfd); + if (fd == STDOUT_FILENO) return 1; + return 0; +} + +NSAPI_PUBLIC int net_is_STDIN(SYS_NETFD prfd) +{ + int fd = PR_FileDesc2NativeHandle(prfd); + if (fd == STDIN_FILENO) return 1; + return 0; +} + +#endif /* XP_UNIX */ + +/* -------------------------- Accept mutex crap --------------------------- */ + + +#ifndef NET_WINSOCK + + +#include "sem.h" +static SEMAPHORE mob_sem; +static int have_mob_sem; + + +void net_accept_enter(void) +{ + if(sem_grab(mob_sem) == -1) + ereport(LOG_CATASTROPHE, "sem_grab failed (%s)", system_errmsg()); + have_mob_sem = 1; +} + +int net_accept_tenter(void) +{ + int ret = sem_tgrab(mob_sem); + if(ret != -1) + have_mob_sem = 1; + return ret; +} + +void net_accept_exit(void) +{ + if(sem_release(mob_sem) == -1) + ereport(LOG_CATASTROPHE, "sem_release failed (%s)", system_errmsg()); + have_mob_sem = 0; +} + +#ifdef AIX +#undef accept +#define accept naccept +#endif + +void net_accept_texit(void) +{ + if(have_mob_sem && (sem_release(mob_sem) == -1)) + ereport(LOG_CATASTROPHE, "sem_release failed (%s)", system_errmsg()); + have_mob_sem = 0; +} + +int net_accept_init(int port) +{ + /* XXXMB how to translate this to nspr? */ + /* since SSL_AcceptHook is no longer in ns security (HCL_1_5), + so this is gone! (It does exist in HCL_101) + SSL_AcceptHook((SSLAcceptFunc)PR_Accept); + */ + have_mob_sem = 0; + mob_sem = sem_init("netsite", port); + return (mob_sem == SEM_ERROR ? -1 : 0); +} + +void net_accept_terminate(void) +{ + sem_terminate(mob_sem); +} + +#endif /* !NET_WINSOCK */ + + +/* ----------------------------- net_ip2host ------------------------------ */ + + +char *dns_ip2host(char *ip, int verify); + +NSAPI_PUBLIC char *net_ip2host(char *ip, int verify) +{ + if(!net_enabledns) + return NULL; + + return dns_ip2host(ip, verify); +} + + + +/* ---------------------------- util_hostname ----------------------------- */ + + + +#ifdef XP_UNIX +#include <sys/param.h> +#else /* WIN32 */ +#define MAXHOSTNAMELEN 255 +#endif /* XP_UNIX */ + +/* Defined in dns.c */ +char *net_find_fqdn(PRHostEnt *p); + +NSAPI_PUBLIC char *util_hostname(void) +{ + char str[MAXHOSTNAMELEN]; + PRHostEnt hent; + char buf[PR_NETDB_BUF_SIZE]; + PRStatus err; + + gethostname(str, MAXHOSTNAMELEN); + err = PR_GetHostByName( + str, + buf, + PR_NETDB_BUF_SIZE, + &hent); + + if (err == PR_FAILURE) + return NULL; + return net_find_fqdn(&hent); +} + + diff --git a/lib/base/nscperror.c b/lib/base/nscperror.c new file mode 100644 index 00000000..9d791f89 --- /dev/null +++ b/lib/base/nscperror.c @@ -0,0 +1,162 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* nscperrors.c + * Very crude error handling for nspr and libsec. + */ + +#include "netsite.h" + +#define NSCP_NSPR_ERROR_BASE (-6000) +#define NSCP_NSPR_MAX_ERROR (NSCP_NSPR_ERROR_BASE + 29) +#define NSCP_LIBSEC_ERROR_BASE (-8192) +#define NSCP_LIBSEC_MAX_ERROR (NSCP_LIBSEC_ERROR_BASE + 63) +#define NSCP_LIBSSL_ERROR_BASE (-12288) +#define NSCP_LIBSSL_MAX_ERROR (NSCP_LIBSSL_ERROR_BASE + 19) + +typedef struct nscp_error_t { + int errorNumber; + const char *errorString; +} nscp_error_t; + +nscp_error_t nscp_nspr_errors[] = { + { 0, "NSPR error" }, + { 1, "Out of memory" }, + { 2, "Bad file descriptor" }, + { 3, "Data temporarily not available" }, + { 4, "Access fault" }, + { 5, "Invalid method" }, + { 6, "Illegal access" }, + { 7, "Unknown error" }, + { 8, "Pending interrupt" }, + { 9, "Not implemented" }, + { 10, "IO error" }, + { 11, "IO timeout error" }, + { 12, "IO already pending error" }, + { 13, "Directory open error" }, + { 14, "Invalid Argument" }, + { 15, "Address not available" }, + { 16, "Address not supported" }, + { 17, "Already connected" }, + { 18, "Bad address" }, + { 19, "Address already in use" }, + { 20, "Connection refused" }, + { 21, "Network unreachable" }, + { 22, "Connection timed out" }, + { 23, "Not connected" }, + { 24, "Load library error" }, + { 25, "Unload library error" }, + { 26, "Find symbol error" }, + { 27, "Connection reset by peer" }, + { 28, "Range Error" }, + { 29, "File Not Found Error" } +}; + +nscp_error_t nscp_libsec_errors[] = { + { 0, "SEC_ERROR_IO" }, + { 1, "SEC_ERROR_LIBRARY_FAILURE" }, + { 2, "SEC_ERROR_BAD_DATA" }, + { 3, "SEC_ERROR_OUTPUT_LEN" }, + { 4, "SEC_ERROR_INPUT_LEN" }, + { 5, "SEC_ERROR_INVALID_ARGS" }, + { 6, "SEC_ERROR_INVALID_ALGORITHM" }, + { 7, "SEC_ERROR_INVALID_AVA" }, + { 8, "SEC_ERROR_INVALID_TIME" }, + { 9, "SEC_ERROR_BAD_DER" }, + { 10, "SEC_ERROR_BAD_SIGNATURE" }, + { 11, "SEC_ERROR_EXPIRED_CERTIFICATE" }, + { 12, "SEC_ERROR_REVOKED_CERTIFICATE" }, + { 13, "SEC_ERROR_UNKNOWN_ISSUER" }, + { 14, "SEC_ERROR_BAD_KEY" }, + { 15, "SEC_ERROR_BAD_PASSWORD" }, + { 16, "SEC_ERROR_UNUSED" }, + { 17, "SEC_ERROR_NO_NODELOCK" }, + { 18, "SEC_ERROR_BAD_DATABASE" }, + { 19, "SEC_ERROR_NO_MEMORY" }, + { 20, "SEC_ERROR_UNTRUSTED_ISSUER" }, + { 21, "SEC_ERROR_UNTRUSTED_CERT" }, + { 22, "SEC_ERROR_DUPLICATE_CERT" }, + { 23, "SEC_ERROR_DUPLICATE_CERT_TIME" }, + { 24, "SEC_ERROR_ADDING_CERT" }, + { 25, "SEC_ERROR_FILING_KEY" }, + { 26, "SEC_ERROR_NO_KEY" }, + { 27, "SEC_ERROR_CERT_VALID" }, + { 28, "SEC_ERROR_CERT_NOT_VALID" }, + { 29, "SEC_ERROR_CERT_NO_RESPONSE" }, + { 30, "SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE" }, + { 31, "SEC_ERROR_CRL_EXPIRED" }, + { 32, "SEC_ERROR_CRL_BAD_SIGNATURE" }, + { 33, "SEC_ERROR_CRL_INVALID" }, + { 34, "SEC_ERROR_" }, + { 35, "SEC_ERROR_" }, + { 36, "SEC_ERROR_" }, + { 37, "SEC_ERROR_" }, + { 38, "SEC_ERROR_" }, + { 39, "SEC_ERROR_" }, + { 40, "SEC_ERROR_" }, + { 41, "SEC_ERROR_" }, + { 42, "SEC_ERROR_" }, + { 43, "SEC_ERROR_" }, + { 44, "SEC_ERROR_" }, + { 45, "SEC_ERROR_" }, + { 46, "SEC_ERROR_" }, + { 47, "SEC_ERROR_" }, + { 48, "SEC_ERROR_" }, + { 49, "SEC_ERROR_" }, + { 50, "SEC_ERROR_" }, + { 51, "SEC_ERROR_" }, + { 52, "SEC_ERROR_" }, + { 53, "SEC_ERROR_" }, + { 54, "SEC_ERROR_" }, + { 55, "SEC_ERROR_" }, + { 56, "SEC_ERROR_" }, + { 57, "SEC_ERROR_" }, + { 58, "SEC_ERROR_" }, + { 59, "SEC_ERROR_" }, + { 60, "SEC_ERROR_" }, + { 61, "SEC_ERROR_" }, + { 62, "SEC_ERROR_" }, + { 63, "SEC_ERROR_NEED_RANDOM" } +}; + +nscp_error_t nscp_libssl_errors[] = { + { 0, "SSL_ERROR_EXPORT_ONLY_SERVER" }, + { 1, "SSL_ERROR_US_ONLY_SERVER" }, + { 2, "SSL_ERROR_NO_CYPHER_OVERLAP" }, + { 3, "SSL_ERROR_NO_CERTIFICATE" }, + { 4, "SSL_ERROR_BAD_CERTIFICATE" }, + { 5, "unused SSL error #5" }, + { 6, "SSL_ERROR_BAD_CLIENT - the server has encountered bad data from the client." }, + { 7, "SSL_ERROR_BAD_SERVER" }, + { 8, "SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE" }, + { 9, "SSL_ERROR_UNSUPPORTED_VERSION" }, + { 10, "unused SSL error #10" }, + { 11, "SSL_ERROR_WRONG_CERTIFICATE" }, + { 12, "SSL_ERROR_BAD_CERT_DOMAIN" }, + { 13, "SSL_ERROR_POST_WARNING" }, + { 14, "SSL_ERROR_SSL2_DISABLED" }, + { 15, "SSL_ERROR_BAD_MAC_READ - SSL has received a record with an incorrect Message Authentication Code." }, + { 16, "SSL_ERROR_BAD_MAC_ALERT - SSL has received an error indicating an incorrect Message Authentication Code." }, + { 17, "SSL_ERROR_BAD_CERT_ALERT - the server cannot verify your certificate." }, + { 18, "SSL_ERROR_REVOKED_CERT_ALERT - the server has rejected your certificate as revoked." }, + { 19, "SSL_ERROR_EXPIRED_CERT_ALERT - the server has rejected your certificate as expired." }, +}; + +const char * +nscperror_lookup(int error) +{ + if ((error >= NSCP_NSPR_ERROR_BASE) && + (error <= NSCP_NSPR_MAX_ERROR)) { + return nscp_nspr_errors[error-NSCP_NSPR_ERROR_BASE].errorString; + } else if ((error >= NSCP_LIBSEC_ERROR_BASE) && + (error <= NSCP_LIBSEC_MAX_ERROR)) { + return nscp_libsec_errors[error-NSCP_LIBSEC_ERROR_BASE].errorString; + } else if ((error >= NSCP_LIBSSL_ERROR_BASE) && + (error <= NSCP_LIBSSL_MAX_ERROR)) { + return nscp_libssl_errors[error-NSCP_LIBSSL_ERROR_BASE].errorString; + } else { + return (const char *)NULL; + } +} diff --git a/lib/base/nterrors.cpp b/lib/base/nterrors.cpp new file mode 100644 index 00000000..2eaf29b3 --- /dev/null +++ b/lib/base/nterrors.cpp @@ -0,0 +1,83 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * nterrors.c: Conversion of error numbers to explanation strings + * + * Aruna Victor 12/6/95 + */ + + +#include <windows.h> +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <netsite.h> +#include <base/nterrors.h>
+#include <base/nterr.h> + +struct _NtHashedError { + int ErrorNumber; + char *ErrorString; + struct _NtHashedError *next; +} ; + +typedef struct _NtHashedError NtHashedError; + +NtHashedError *hashedNtErrors[200]; + +#define HASH_ERROR_MODULUS 199 +#define DEFAULT_ERROR_STRING "Error Number is unknown" + +char * +FindError(int error) +{ + NtHashedError *tmp; + + int hashValue = error % HASH_ERROR_MODULUS; + tmp = hashedNtErrors[hashValue]; + + while(tmp) { + if (tmp->ErrorNumber == error) { + return tmp->ErrorString; + } + tmp = tmp->next; + } + return(DEFAULT_ERROR_STRING); +} + +void +EnterError(NtHashedError *error) +{ + NtHashedError *tmp; + int hashValue; + int number = 199; + + hashValue = error->ErrorNumber % HASH_ERROR_MODULUS; + + if(!(tmp = hashedNtErrors[hashValue])){ + hashedNtErrors[hashValue] = error; + } else { + while(tmp->next) { + tmp = tmp->next; + } + tmp->next = error; + } +} +
+void +HashNtErrors() +{ + NtHashedError *error; + int i = 0; + + while(NtErrorStrings[i].ErrorString) { + error = (NtHashedError *)MALLOC(sizeof(NtHashedError)); + error->ErrorNumber = NtErrorStrings[i].ErrorNumber; + error->ErrorString = NtErrorStrings[i++].ErrorString; + error->next = NULL; + EnterError(error); + } +}
\ No newline at end of file diff --git a/lib/base/plist.cpp b/lib/base/plist.cpp new file mode 100644 index 00000000..fe9d909e --- /dev/null +++ b/lib/base/plist.cpp @@ -0,0 +1,1154 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * MODULE: plist.c + * + * DESCRIPTION: + * + * This module implements property lists. A property list is an + * ordered array of property values. Each property value has an + * handle for some data item, and may have a reference to + * another property list which describes the type of the data + * item. Each property value has a property index which specifies + * its position in the property list. A property value may also + * have a name. Since the data item associated with a property + * value may reference another property list, it is possible to + * construct arbitrary linked structures of property lists. + * + * IMPLEMENTATION NOTES: + */ + +#include "netsite.h" +#include "base/plist.h" +#include "plist_pvt.h" + +int plistHashSizes[] = PLSTSIZES; + +/* + * FUNCTION: PListAssignValue + * + * DESCRIPTION: + * + * This function sets the value and/or type of a defined property + * in given property list. If the property type is specified as + * NULL, it is unchanged. However, the property value is always + * set to the specified value. + * + * ARGUMENTS: + * + * plist - handle for the property list + * pname - the property name + * pvalue - the new property value + * ptype - the new property type, or NULL + * + * RETURNS: + * + * If successful, the property index of the referenced property is + * returned as the function value. Errors are indicated by a + * negative return code as defined in plist.h. + */ + +NSAPI_PUBLIC int +PListAssignValue(PList_t plist, const char *pname, + const void *pvalue, PList_t ptype) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t *pv; + int pindex; + int i; + + if (!plist) return ERRPLUNDEF; + + /* Got a symbol table for this property list? */ + if (pl->pl_symtab) { + + /* Yes, compute hash of specified name */ + i = PListHashName(pl->pl_symtab, pname); + + /* Search hash collision list for matching name */ + for (pv = pl->pl_symtab->pt_hash[i]; pv; pv = pv->pv_next) { + + if (!strcmp(pname, pv->pv_name)) { + + /* Name match, get property index */ + pindex = pv->pv_pi; + + /* Set the new value */ + pv->pv_value = (char *)pvalue; + + /* Set type if type is given */ + if (ptype) pv->pv_type = (PListStruct_t *)ptype; + + /* Return the property index */ + return pindex; + } + } + } + + /* Error - specified property name is undefined */ + return ERRPLUNDEF; +} + +/* + * FUNCTION: PListCreate + * + * DESCRIPTION: + * + * This function creates a new property list and returns a handle for + * it. It allows the caller to reserve a specified number of + * property indices at the beginning of the list, and also to limit + * the total number of property values that may be added to the list. + * + * ARGUMENTS: + * + * mempool - handle for a memory pool to be associated + * with the new property list + * resvprop - number of reserved property indices + * maxprop - maximum number of properties in list + * (zero or negative imposes no limit) + * flags - unused, reserved, must be zero + * + * RETURNS: + * + * If successful, the function return value is a handle for the new + * property list. Otherwise NULL is returned. + */ + +NSAPI_PUBLIC PList_t +PListCreate(pool_handle_t *mempool, int resvprop, int maxprop, int flags) +{ + PListStruct_t *plist; /* pointer to property list structure */ + int i; + + plist = (PListStruct_t *)pool_malloc(mempool, sizeof(PListStruct_t)); + if (plist) { + + /* Negative maxprop is the same as zero, i.e. no limit */ + if (maxprop < 0) maxprop = 0; + + /* If resvprop and maxprop are both specified, limit resvprop */ + if (resvprop > 0) { + if (maxprop && (resvprop > maxprop)) resvprop = maxprop; + } + else resvprop = 0; + + /* Initialize property list structure */ + plist->pl_mempool = mempool; + plist->pl_symtab = NULL; + plist->pl_maxprop = maxprop; + plist->pl_resvpi = resvprop; + plist->pl_initpi = resvprop; + plist->pl_lastpi = resvprop; + + /* Set initialize size for array of property value pointers */ + plist->pl_cursize = (resvprop) ? resvprop : PLIST_DEFSIZE; + + /* Allocate the initial array of property value pointers */ + plist->pl_ppval = (pb_entry **)pool_malloc(mempool, + (plist->pl_cursize * + sizeof(PLValueStruct_t *))); + if (!plist->pl_ppval) { + + /* Failed - insufficient memory */ + pool_free(mempool, (void *)plist); + plist = NULL; + } + else { + /* NULL out pointers in the reserved index range, if any */ + for (i = 0; i < plist->pl_lastpi; ++i) { + plist->pl_ppval[i] = 0; + } + } + } + + return (PList_t)plist; +} + +/* + * FUNCTION: PListDefProp + * + * DESCRIPTION: + * + * This function creates a new property in a specified property list. + * The 'pindex' argument may be used to request a particular property + * index for the new property. If 'pindex' is greater than zero, + * the specified value is used as the new property's index, provided + * there is no property at that index already. If 'pindex' is zero, + * then the next available property index is assigned to the new + * property. A name may optionally be specified for the new property. + * + * ARGUMENTS: + * + * plist - handle for the property list + * pindex - new property index (or zero) + * pname - new property name (or NULL) + * + * RETURNS: + * + * If successful, the index of the new property is returned as the + * function value. Errors are indicated by a negative return code + * as defined in plist.h. + */ + +NSAPI_PUBLIC int +PListDefProp(PList_t plist, int pindex, const char *pname, const int flags) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t **ppval; + PLValueStruct_t *pv; + int cursize; + int i; + int wrapped; + + if (!plist) return ERRPLUNDEF; + + ppval = (PLValueStruct_t **)(pl->pl_ppval); + + /* Is pindex specified? */ + if (pindex > 0) { + + /* Yes, is it in the reserved range? */ + if (flags != PLFLG_IGN_RES && pindex > pl->pl_resvpi) { + /* No, error */ + return ERRPLINVPI; + } + + i = pindex - 1; + + if (ppval[i]) { + /* Error - property already exists at specified index */ + return ERRPLEXIST; + } + } + else { + + /* + * Look for a free property index, starting at pl_lastpi + 1. + * (Note that i is the property index - 1) + */ + for (wrapped = 0, i = pl->pl_lastpi; ;) { + + /* Are we in an initialized part of the array? */ + if (i < pl->pl_initpi) { + + /* Yes, use this index if it's free */ + if (ppval[i] == 0) break; + + /* Otherwise step to the next one */ + ++i; + } + else { + + /* Have we reached the end yet? */ + if (i < pl->pl_cursize) { + + /* + * We are above the highest initialized index, but + * still within the allocated size. An index in + * this range can be used with no further checks. + */ + ppval[i] = 0; + } + else { + + /* + * It's looking like time to grow the array, but + * first go back and look for an unused, unreserved + * index that might have been freed. + */ + if (!wrapped) { + + i = pl->pl_resvpi; + wrapped = 1; + continue; + } + + /* + * Grow the array unless there is a specified maximum + * size and we've reached it. + */ + i = pl->pl_cursize; + if (pl->pl_maxprop && (i > pl->pl_maxprop)) { + + /* Error - property list is full */ + return ERRPLFULL; + } + + /* Increase planned size of list */ + cursize = i + PLIST_DEFGROW; + + /* Reallocate the array of property value pointers */ + ppval = (PLValueStruct_t **)pool_realloc(pl->pl_mempool, + (void *)ppval, + (cursize * sizeof(PLValueStruct_t *))); + if (!ppval) { + + /* Error - insufficient memory */ + return ERRPLNOMEM; + } + + /* Initialize the first new entry and select it */ + ppval[i] = NULL; + pl->pl_ppval = (pb_entry **)ppval; + pl->pl_cursize = cursize; + } + + /* Update the highest initialized index value */ + pl->pl_initpi = i + 1; + break; + } + } + + /* Set the starting point for the next allocation */ + pl->pl_lastpi = i + 1; + } + + /* We have a property index (i + 1). Create a new property value */ + pv = (PLValueStruct_t *)pool_calloc(pl->pl_mempool, + 1, sizeof(PLValueStruct_t)); + if (!pv) { + + /* Error - insufficient memory */ + return ERRPLNOMEM; + } + + pv->pv_pbentry.param = &pv->pv_pbparam; + pv->pv_pi = i + 1; + ppval[i] = pv; + + /* Name the property if the name was specified */ + if (pname) { + + /* XXX Maybe should delete property if naming fails */ + return PListNameProp(plist, i + 1, pname); + } + + /* Return the property index of the new property */ + return i + 1; +} + +/* + * FUNCTION: PListDeleteProp + * + * DESCRIPTION: + * + * This function deletes a property from a specified property list. + * The property can be specified by its property index, using a + * pindex value greater than zero, or by its name, by specifying + * pindex as zero and pname as the property name. This does not + * have any effect on the data referenced by the property value, + * if any, nor does it have any effect on the property list that + * describes the property value's type, if any. + * + * ARGUMENTS: + * + * plist - handle for the property list + * pindex - the property index, or zero + * pname - the property name, or NULL + */ + +NSAPI_PUBLIC const void * +PListDeleteProp(PList_t plist, int pindex, const char *pname_in) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t **ppval; + PLValueStruct_t **pvp; + PLValueStruct_t *pv = NULL; + int i; + const void *pvalue = NULL; + char *pname = (char *)pname_in; + + if (!plist) return NULL; + + ppval = (PLValueStruct_t **)(pl->pl_ppval); + + /* Check for valid property index */ + if ((pindex > 0) && (pindex <= pl->pl_initpi)) { + + /* Get the pointer to the property structure */ + pv = ppval[pindex - 1]; + pname = 0; + if (pv) { + pname = pv->pv_name; + } + } + + if (pname && pl->pl_symtab) { + + /* Compute hash of specified property name */ + i = PListHashName(pl->pl_symtab, pname); + + /* Search hash collision list for matching name */ + for (pvp = &pl->pl_symtab->pt_hash[i]; *pvp; pvp = &(*pvp)->pv_next) { + + pv = *pvp; + if (!strcmp(pname, pv->pv_name)) { + + /* Found it. Get its index and remove it. */ + pindex = pv->pv_pi; + *pvp = pv->pv_next; + break; + } + } + } + + /* Found the indicated property by index or name? */ + if (pv) { + + /* Yes, remove it from the property list */ + ppval[pindex - 1] = NULL; + + /* Free the property name, if any */ + if (pv->pv_name) { + pool_free(pl->pl_mempool, (void *)(pv->pv_name)); + } + pvalue = pv->pv_value; + + /* Free the property */ + pool_free(pl->pl_mempool, (void *)pv); + } + return(pvalue); +} + +/* + * FUNCTION: PListFindValue + * + * DESCRIPTION: + * + * This function retrieves the value and type of a property with a + * specified property name. If the pvalue argument is non-NULL, + * it specifies a location in which to return the property value. + * Similarly, if ptype is non-NULL, it specifies where the property + * list describing the property type is to be returned. If a + * property has no value, the value returned for pvalue is NULL. + * If a property has no type, the value returned for ptype is NULL. + * A property can have a value, a type, both, or neither. + * + * ARGUMENTS: + * + * plist - handle for the property list + * pname - pointer to property name string + * pvalue - property value return pointer + * ptype - property type return pointer + * + * RETURNS: + * + * If successful, the index of the referenced property is returned + * as the function value. Errors are indicated by a negative + * return code as defined in plist.h. + */ + +NSAPI_PUBLIC int +PListFindValue(PList_t plist, const char *pname, void **pvalue, PList_t *ptype) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t *pv; + int pindex; + int i; + + if (!plist) return ERRPLUNDEF; + + /* Got a symbol table for this property list? */ + if (pl->pl_symtab) { + + /* Yes, compute hash of specified name */ + i = PListHashName(pl->pl_symtab, pname); + + /* Search hash collision list for matching name */ + for (pv = pl->pl_symtab->pt_hash[i]; pv; pv = pv->pv_next) { + + if (!strcmp(pname, pv->pv_name)) { + + /* Name match, get property index */ + pindex = pv->pv_pi; + + /* Return the value if requested */ + if (pvalue) *pvalue = (void *)(pv->pv_value); + + /* Return the type if requested */ + if (ptype) *ptype = (PList_t)(pv->pv_type); + + /* Return the property index */ + return pindex; + } + } + } + + /* Error - specified property name is undefined */ + return ERRPLUNDEF; +} + +/* + * FUNCTION: PListInitProp + * + * DESCRIPTION: + * + * This function combines the functions of PListDefProp() and + * PListSetValue(), defining a new property and assigning it an + * initial value and optionally a type and/or a name. + * + * ARGUMENTS: + * + * plist - handle for the property list + * pindex - a reserved property index, or zero + * pname - the new property name, or NULL + * pvalue - the new property value + * ptype - the new property type, or NULL + * + * RETURNS: + * + * If successful, the property index (pindex) is returned as the + * function value. Errors are indicated by a negative return code + * as defined in plist.h. + */ + +NSAPI_PUBLIC int +PListInitProp(PList_t plist, int pindex, const char *pname, + const void *pvalue, PList_t ptype) +{ + int rv; + + if (!plist) return ERRPLUNDEF; + + /* Create the property */ + rv = PListDefProp(plist, pindex, pname, PLFLG_USE_RES); + if (rv > 0) { + + /* If that worked, set the value and type */ + rv = PListSetValue(plist, rv, pvalue, ptype); + } + + return rv; +} + +/* + * FUNCTION: PListNew + * + * DESCRIPTION: + * + * This function creates a new property list, using the specified + * memory pool for allocating the internal data structures used to + * represent it. If the mempool argument is NULL, the default + * memory pool is used. + * + * ARGUMENTS: + * + * mempool - handle for a memory pool to be associated + * with the new property list + * + * RETURNS: + * + * If successful, the function return value is a handle for the new + * property list. Otherwise NULL is returned. + */ + +NSAPI_PUBLIC PList_t +PListNew(pool_handle_t *mempool) +{ + /* Just call PListCreate with default parameters */ + return PListCreate(mempool, 0, 0, 0); +} + +/* + * FUNCTION: PListDestroy + * + * DESCRIPTION: + * + * This function destroys a specified property list. This means + * that any dynamic memory which was allocated as a result of calls + * to the property list API is freed to the memory pool from which + * it was allocated. Property value data is not freed, nor are + * any property lists associated with property types. + * + * ARGUMENTS: + * + * plist - handle for the property list + */ + +void +PListDestroy(PList_t plist) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t **ppval; + PLValueStruct_t *pv; + int i; + + if (!plist) return; + + /* Free the property name symbol table if any */ + if (pl->pl_symtab) { + pool_free(pl->pl_mempool, (void *)(pl->pl_symtab)); + } + + ppval = (PLValueStruct_t **)(pl->pl_ppval); + + /* Loop over the initialized property indices */ + for (i = 0; i < pl->pl_initpi; ++i) { + + /* Got a property here? */ + pv = ppval[i]; + if (pv) { + + /* Free the property name string if any */ + if (pv->pv_name) { + pool_free(pl->pl_mempool, (void *)(pv->pv_name)); + } + + /* Free the property value structure */ + pool_free(pl->pl_mempool, (void *)pv); + } + } + + /* Free the array of pointers to property values */ + pool_free(pl->pl_mempool, (void *)ppval); + + /* Free the property list head */ + pool_free(pl->pl_mempool, (void *)pl); +} + +/* + * FUNCTION: PListGetValue + * + * DESCRIPTION: + * + * This function retrieves the value and type of the property with + * the property index given by pindex in the specified property + * list. The pindex argument must specify the index of a defined + * property. If the pvalue argument is non-NULL, it specifies a + * location in which to return the property value. Similarly, if + * ptype is non-NULL, it specifies where the property list + * describing the property type is to be returned. If a property + * has no value, the value returned for pvalue is NULL. If a + * property has no type, the value returned for ptype is NULL. A + * property can have a value, a type, both, or neither. + * + * ARGUMENTS: + * + * plist - handle for the property list + * pindex - the property index + * pvalue - property value return pointer + * ptype - property type return pointer + * + * RETURNS: + * + * If successful, the property index (pindex) is returned as the + * function value. Errors are indicated by a negative return code + * as defined in plist.h. + */ + +NSAPI_PUBLIC int +PListGetValue(PList_t plist, int pindex, void **pvalue, PList_t *ptype) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t **ppval; + PLValueStruct_t *pv; + + if (!plist) return ERRPLUNDEF; + + ppval = (PLValueStruct_t **)(pl->pl_ppval); + + /* Check for valid property index */ + if ((pindex > 0) && (pindex <= pl->pl_initpi)) { + + /* Does the property exist? */ + pv = ppval[pindex - 1]; + if (pv) { + + /* Yes, return the value if requested */ + if (pvalue) *pvalue = (void *)(pv->pv_value); + + /* Return the type if requested */ + if (ptype) *ptype = (PList_t)(pv->pv_type); + + /* Successful return */ + return pindex; + } + } + + /* Error - invalid property index or non-existent property */ + return ERRPLINVPI; +} + +/* + * FUNCTION: PListHashName + * + * DESCRIPTION: + * + * This function hashes a given property name for a specified + * symbol table. It produces a value that can be used as an + * index in the pt_hash array associated with the symbol table. + * + * ARGUMENTS: + * + * symtab - pointer to the symbol table + * pname - pointer to the property name string + * + * RETURNS: + * + * The hash index is returned as the function value. + */ + +int +PListHashName(PLSymbolTable_t *symtab, const char *pname) +{ + unsigned int hashval = 0; /* hash value */ + + while (*pname) { + hashval = (hashval<<5) ^ (*pname++ & 0x7f); + } + + return hashval % PLSIZENDX(symtab->pt_sizendx); +} + +/* + * FUNCTION: PListNameProp + * + * DESCRIPTION: + * + * This function assigns a name to a defined property with the + * property index, pindex. If the property has an existing name, + * it will be replaced with the name specified by pname. + * + * ARGUMENTS: + * + * plist - handle for the property list + * pindex - the property index + * pname - the new property name + * + * RETURNS: + * + * If successful, the property index (pindex) is returned as the + * function value. Errors are indicated by a negative return code + * as defined in plist.h. + */ + +NSAPI_PUBLIC int +PListNameProp(PList_t plist, int pindex, const char *pname) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t *pv; + PLSymbolTable_t *pt; + int i; + + if (!plist) return ERRPLUNDEF; + + pt = pl->pl_symtab; + + /* Check for valid property index */ + if ((pindex > 0) && (pindex <= pl->pl_initpi)) { + + /* Does the property exist? */ + pv = ((PLValueStruct_t **)(pl->pl_ppval))[pindex - 1]; + if (pv) { + + /* If it has a name already, unname it */ + if (pv->pv_name) { + PLValueStruct_t **pvp; + + /* Get hash bucket index */ + i = PListHashName(pt, pv->pv_name); + + /* Seach hash collision list for this property */ + for (pvp = &pt->pt_hash[i]; + *pvp; pvp = &(*pvp)->pv_next) { + + if (*pvp == pv) { + + /* Remove it from the list */ + *pvp = pv->pv_next; + break; + } + } + + /* Free the current name string */ + pool_free(pl->pl_mempool, (void *)(pv->pv_name)); + } + + /* Got a new name? */ + if (pname) { + + /* Yes, is there a hash table? */ + if (!pt) { + + /* No, create one */ + pt = (PLSymbolTable_t *)pool_calloc(pl->pl_mempool, 1, + PLHASHSIZE(0)); + if (!pt) { + return ERRPLNOMEM; + } + + pl->pl_symtab = pt; + } + else { + + /* Is it time to grow the hash table? */ + i = PLSIZENDX(pt->pt_sizendx); + if ((pt->pt_sizendx < PLMAXSIZENDX) && + pt->pt_nsyms >= (i + i)) { + + PLSymbolTable_t *npt; + + /* Yes, allocate the new table */ + npt = (PLSymbolTable_t *)pool_calloc(pl->pl_mempool, 1, + PLHASHSIZE(pt->pt_sizendx+1)); + if (npt) { + PLValueStruct_t *opv; + PLValueStruct_t *npv; + int j; + + npt->pt_sizendx = pt->pt_sizendx + 1; + npt->pt_nsyms = pt->pt_nsyms; + + /* Rehash all the names into the new table */ + for (i = 0; i < PLSIZENDX(pt->pt_sizendx); ++i) { + for (opv = pt->pt_hash[i]; opv; opv = npv) { + npv = opv->pv_next; + j = PListHashName(npt, opv->pv_name); + opv->pv_next = npt->pt_hash[j]; + npt->pt_hash[j] = opv; + } + } + + pl->pl_symtab = npt; + + /* Free the old symbol table */ + pool_free(pl->pl_mempool, (void *)pt); + pt = npt; + } + } + } + + /* Duplicate the name string */ + pv->pv_name = pool_strdup(pl->pl_mempool, (char *)pname); + + /* Add name to symbol table */ + i = PListHashName(pt, pname); + pv->pv_next = pt->pt_hash[i]; + pt->pt_hash[i] = pv; + } + + /* Successful return */ + return pindex; + } + } + + /* Error - invalid property index or non-existent property */ + return ERRPLINVPI; +} + +/* + * FUNCTION: PListSetType + * + * DESCRIPTION: + * + * This function sets the property type of the defined property + * with the property index, pindex. The property list describing + * the property type is specified by ptype. If ptype is NULL, + * the property type will be set to be undefined (NULL). + * + * + * ARGUMENTS: + * + * plist - handle for the property list + * pindex - the property index + * ptype - the new property type, or NULL + * + * RETURNS: + * + * If successful, the property index (pindex) is returned as the + * function value. Errors are indicated by a negative return code + * as defined in plist.h. + */ + +NSAPI_PUBLIC int +PListSetType(PList_t plist, int pindex, PList_t ptype) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t **ppval; + PLValueStruct_t *pv; + + if (!plist) return ERRPLUNDEF; + + ppval = (PLValueStruct_t **)(pl->pl_ppval); + + /* Check for valid property index */ + if ((pindex > 0) && (pindex <= pl->pl_initpi)) { + + /* Does the property exist? */ + pv = ppval[pindex - 1]; + if (pv) { + + /* Yes, set the new type */ + pv->pv_type = ptype; + + /* Successful return */ + return pindex; + } + } + + /* Error - invalid property index or non-existent property */ + return ERRPLINVPI; +} + +/* + * FUNCTION: PListSetValue + * + * DESCRIPTION: + * + * This function sets the value and optionally the type of a + * defined property in a given property list. The pindex argument + * specifies the property index, which must be greater than zero. + * The ptype argument specifies a property list that describes the + * property type. If ptype is NULL, the property type, if any, is + * unchanged by this function. However, the property value is + * always set to the value given by pvalue. + * + * ARGUMENTS: + * + * plist - handle for the property list + * pindex - the property index + * pvalue - the new property value + * ptype - the new property type, or NULL + * + * RETURNS: + * + * If successful, the property index (pindex) is returned as the + * function value. Errors are indicated by a negative return code + * as defined in plist.h. + */ + +NSAPI_PUBLIC int +PListSetValue(PList_t plist, int pindex, const void *pvalue, PList_t ptype) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t **ppval; + PLValueStruct_t *pv; + + if (!plist) return ERRPLUNDEF; + + ppval = (PLValueStruct_t **)(pl->pl_ppval); + + /* Check for valid property index */ + if ((pindex > 0) && (pindex <= pl->pl_initpi)) { + + /* Does the property exist? */ + pv = ppval[pindex - 1]; + if (pv) { + + /* Yes, set the new value */ + pv->pv_value = (char *)pvalue; + + /* Set type if type is given */ + if (ptype) pv->pv_type = (PListStruct_t *)ptype; + + /* Successful return */ + return pindex; + } + } + + /* Error - invalid property index or non-existent property */ + return ERRPLINVPI; +} + +/* + * FUNCTION: PListEnumerate + * + * DESCRIPTION: + * + * This function walks through a specified property list + * calling a user supplied function with the property + * name and value as parameters. + * + * ARGUMENTS: + * + * plist - handle for the property list + * user_func - handle for the user function + */ + +NSAPI_PUBLIC void +PListEnumerate(PList_t plist, PListFunc_t *user_func, void *user_data) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t **ppval; + PLValueStruct_t *pv; + int i; + + if (!plist) return; + + ppval = (PLValueStruct_t **)(pl->pl_ppval); + + /* Loop over the initialized property indices */ + for (i = 0; i < pl->pl_initpi; ++i) { + + /* Got a property here? */ + pv = ppval[i]; + if (pv) { + (*user_func)(pv->pv_name, pv->pv_value, user_data); + } + + } + +} + +/* + * FUNCTION: PListCreateDuplicate + * + * DESCRIPTION: + * + * This function creates a new property list and returns a handle for + * it. The source plist provides the new plists parameters. + * + * ARGUMENTS: + * + * src_plist - source plist to duplicate + * mempool - handle for a memory pool to be associated + * with the new property list, only + * used if flags is set to PLFLG_NEW_MPOOL + * flags - if PLFLG_NEW_MPOOL uses new_mempool + * parameter + * + * RETURNS: + * + * If successful, the function return value is a handle for the new + * property list. Otherwise NULL is returned. + */ + +static PList_t +PListCreateDuplicate(PList_t src_plist, pool_handle_t *new_mempool, int flags) +{ + PListStruct_t *plist; /* pointer to property list structure */ + int i; + pool_handle_t *mempool; + + mempool = (flags == PLFLG_NEW_MPOOL) ? new_mempool : src_plist->pl_mempool; + + plist = (PListStruct_t *)pool_malloc(mempool, sizeof(PListStruct_t)); + if (plist) { + + /* Initialize property list structure */ + plist->pl_mempool = mempool; + plist->pl_symtab = NULL; + plist->pl_maxprop = src_plist->pl_maxprop; + plist->pl_resvpi = src_plist->pl_resvpi; + plist->pl_initpi = src_plist->pl_initpi; + plist->pl_lastpi = src_plist->pl_lastpi; + + /* Set initialize size for array of property value pointers */ + plist->pl_cursize = src_plist->pl_cursize; + + /* Allocate the initial array of property value pointers */ + plist->pl_ppval = (pb_entry **)pool_malloc(mempool, + (plist->pl_cursize * + sizeof(PLValueStruct_t *))); + if (!plist->pl_ppval) { + + /* Failed - insufficient memory */ + pool_free(mempool, (void *)plist); + plist = NULL; + } + else { + /* NULL out pointers in the reserved index range, if any */ + for (i = 0; i < plist->pl_lastpi; ++i) { + plist->pl_ppval[i] = 0; + } + } + } + + return (PList_t)plist; +} + + +/* + * FUNCTION: PListDuplicate + * + * DESCRIPTION: + * + * This function duplicates a specified PList_t. + * + * ARGUMENTS: + * + * plist - handle for the property list + * mempool - handle for a memory pool to be associated + * with the new property list + * resvprop - number of reserved property indices + * maxprop - maximum number of properties in list + * (zero or negative imposes no limit) + * flags - unused, reserved, must be zero + * + * RETURNS: + * + * If successful, the function return value is a handle for the new + * property list. Otherwise NULL is returned. + */ + +NSAPI_PUBLIC PList_t +PListDuplicate(PList_t plist, pool_handle_t *new_mempool, int flags) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t **ppval; + PLValueStruct_t *pv; + int i; + int rv = 0; + PList_t new_plist; + + if (!plist) return NULL; + + new_plist = PListCreateDuplicate(plist, new_mempool, flags); + if (new_plist == NULL) { + return(NULL); + } + + ppval = (PLValueStruct_t **)(pl->pl_ppval); + + /* Loop over the initialized property indices */ + for (i = 0; i < pl->pl_initpi; ++i) { + + /* Got a property here? */ + pv = ppval[i]; + if (pv) { + /* Create the property */ + rv = PListDefProp(new_plist, i + 1, pv->pv_name, PLFLG_IGN_RES); + if (rv > 0) { + + /* If that worked, set the value and type */ + rv = PListSetValue(new_plist, rv, pv->pv_value, pv->pv_type); + } + + if ( rv <= 0 ) { + PListDestroy(new_plist); + return(NULL); + } + } + + } + + return(new_plist); +} + +/* + * FUNCTION: PListGetPool + * + * DESCRIPTION: + * + * This function returns the memory pool the PList is allocated from. + * + * ARGUMENTS: + * + * plist - handle for the property list + * + * RETURNS: + * + * The memory pool address, which can be NULL. + */ + +NSAPI_PUBLIC pool_handle_t * +PListGetPool(PList_t plist) +{ + if (!plist) return NULL; + + return(plist->pl_mempool); +} + diff --git a/lib/base/plist_pvt.h b/lib/base/plist_pvt.h new file mode 100644 index 00000000..e4b861c5 --- /dev/null +++ b/lib/base/plist_pvt.h @@ -0,0 +1,122 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +#ifndef _PLIST_PVT_H +#define _PLIST_PVT_H + +/* + * FILE: plist_pvt.h + * + * DESCRIPTION: + * + * This file contains private definitions for the property list + * utility implementation. + */ + +#include "base/pool.h" + +/* Forward declarations */ +typedef struct PLValueStruct_s PLValueStruct_t; +typedef struct PLSymbol_s PLSymbol_t; +typedef struct PLSymbolTable_s PLSymbolTable_t; +typedef struct PListStruct_s PListStruct_t; + +/* + * TYPE: PLValueStruct_t + * + * DESCRIPTION: + * + * This type represents a property value. It is dynamically + * allocated when a new property is added to a property list. + * It contains a reference to a property list that contains + * information about the property value, and a reference to + * the property value data. + */ + +#ifndef PBLOCK_H +#include "base/pblock.h" +#endif /* PBLOCK_H */ +#include <stddef.h> + +struct PLValueStruct_s { + pb_entry pv_pbentry; /* used for pblock compatibility */ + pb_param pv_pbparam; /* property name and value pointers */ + PLValueStruct_t *pv_next; /* property name hash collision link */ + PListStruct_t *pv_type; /* property value type reference */ + int pv_pi; /* property index */ + int pv_flags; /* bit flags */ +}; + +#define pv_name pv_pbparam.name +#define pv_value pv_pbparam.value + +/* pv_flags definitions */ +#define PVF_MALLOC 0x1 /* allocated via MALLOC */ + +/* Offset to pv_pbparam in PLValueStruct_t */ +#define PVPBOFFSET offsetof(struct PLValueStruct_s,pv_pbparam) + +/* Convert pb_param pointer to PLValueStruct_t pointer */ +#define PATOPV(p) ((PLValueStruct_t *)((char *)(p) - PVPBOFFSET)) + +/* + * TYPE: PLSymbolTable_t + * + * DESCRIPTION: + * + * This type represents a symbol table that maps property names + * to properties. It is dynamically allocated the first time a + * property is named. + */ + +#define PLSTSIZES {7, 19, 31, 67, 123, 257, 513} +#define PLMAXSIZENDX (sizeof(plistHashSizes)/sizeof(plistHashSizes[0])) + +struct PLSymbolTable_s { + int pt_sizendx; /* pt_hash size, as an index in PLSTSIZES */ + int pt_nsyms; /* number of symbols in table */ + PLValueStruct_t *pt_hash[1];/* variable-length array */ +}; + +/* + * TYPE: PListStruct_t + * + * DESCRIPTION: + * + * This type represents the top-level of a property list structure. + * It is dynamically allocated when a property list is created, and + * freed when the property list is destroyed. It references a + * dynamically allocated array of pointers to property value + * structures (PLValueStruct_t). + */ + +#define PLIST_DEFSIZE 8 /* default initial entries in pl_ppval */ +#define PLIST_DEFGROW 16 /* default incremental entries for pl_ppval */ + +struct PListStruct_s { + pblock pl_pb; /* pblock subset of property list head */ + PLSymbolTable_t *pl_symtab; /* property name to index symbol table */ + pool_handle_t *pl_mempool; /* associated memory pool handle */ + int pl_maxprop; /* maximum number of properties */ + int pl_resvpi; /* number of reserved property indices */ + int pl_lastpi; /* last allocated property index */ + int pl_cursize; /* current size of pl_ppval in entries */ +}; + +#define pl_initpi pl_pb.hsize /* number of pl_ppval entries initialized */ +#define pl_ppval pl_pb.ht /* pointer to array of value pointers */ + +/* Convert pblock pointer to PListStruct_t pointer */ +#define PBTOPL(p) ((PListStruct_t *)(p)) + +#define PLSIZENDX(i) (plistHashSizes[i]) +#define PLHASHSIZE(i) (sizeof(PLSymbolTable_t) + \ + (PLSIZENDX(i) - 1)*sizeof(PLValueStruct_t *)) + +extern int plistHashSizes[7]; + +extern int PListHashName(PLSymbolTable_t *symtab, const char *pname); + +#endif /* _PLIST_PVT_H */ diff --git a/lib/base/pool.cpp b/lib/base/pool.cpp new file mode 100644 index 00000000..56232e3f --- /dev/null +++ b/lib/base/pool.cpp @@ -0,0 +1,654 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * Generic pool handling routines. + * + * Hopefully these reduce the number of malloc/free calls. + * + * + * Thread warning: + * This implementation is thread safe. However, simultaneous + * mallocs/frees to the same "pool" are not safe. If you wish to + * use this module across multiple threads, you should define + * POOL_LOCKING which will make the malloc pools safe. + * + * Mike Belshe + * 11-20-95 + * + */ + +#include "netsite.h" +#include "base/systems.h" +#include "base/systhr.h" + +#ifdef MALLOC_POOLS +#include "base/pool.h" +#include "base/ereport.h" +#include "base/session.h" +#include "frame/req.h" +#include "frame/http.h" +#include "base/util.h" +#include "base/crit.h" + +#include "base/dbtbase.h" + +#ifdef DEBUG +#define POOL_ZERO_DEBUG +#endif +#undef POOL_LOCKING + +#define BLOCK_SIZE (32 * 1024) +#define MAX_FREELIST_SIZE (BLOCK_SIZE * 32) + +/* WORD SIZE 8 sets us up for 8 byte alignment. */ +#define WORD_SIZE 8 +#undef ALIGN +#define ALIGN(x) ( (x + WORD_SIZE-1) & (~(WORD_SIZE-1)) ) + +/* block_t + * When the user allocates space, a BLOCK_SIZE (or larger) block is created in + * the pool. This block is used until all the space is eaten within it. + * When all the space is gone, a new block is created. + * + */ +typedef struct block_t { + char *data; /* the real alloc'd space */ + char *start; /* first free byte in block */ + char *end; /* ptr to end of block */ + struct block_t *next; /* ptr to next block */ +} block_t; + +/* pool_t + * A pool is a collection of blocks. The blocks consist of multiple + * allocations of memory, but a single allocation cannot be freed by + * itself. Once the memory is allocated it is allocated until the + * entire pool is freed. + */ +typedef struct pool_t { +#ifdef DEBUG_CACHES + time_t time_created; +#endif +#ifdef POOL_LOCKING + CRITICAL lock; /* lock for modifying the pool */ +#endif + block_t *curr_block; /* current block being used */ + block_t *used_blocks; /* blocks that are all used up */ + long size; /* size of memory in pool */ + struct pool_t *next; /* known_pools list */ +} pool_t; + +/* known_pools + * Primarily for debugging, keep a list of all active malloc pools. + */ +static pool_t *known_pools = NULL; +static CRITICAL known_pools_lock = NULL; +static unsigned long pool_blocks_created = 0; +static unsigned long pool_blocks_freed = 0; + +/* freelist + * Internally we maintain a list of free blocks which we try to pull from + * whenever possible. This list will never have more than MAX_FREELIST_SIZE + * bytes within it. + */ +static CRITICAL freelist_lock = NULL; +static block_t *freelist = NULL; +static unsigned long freelist_size = 0; +static unsigned long freelist_max = MAX_FREELIST_SIZE; +static int pool_disable = 0; + +int +pool_internal_init() +{ + if (pool_disable == 0) { + if (known_pools_lock == NULL) { + known_pools_lock = crit_init(); + freelist_lock = crit_init(); + } + } else + ereport(LOG_INFORM, XP_GetAdminStr(DBT_poolInitMemoryPoolsDisabled_)); + + return 0; +} + +NSAPI_PUBLIC int +pool_init(pblock *pb, Session *sn, Request *rq) +{ + char *str_free_size = pblock_findval("free-size", pb); + char *str_pool_disable = pblock_findval("disable", pb); + + if (str_free_size != NULL) { + if ( (freelist_max = atoi(str_free_size)) <= 0) { + ereport(LOG_WARN, XP_GetAdminStr(DBT_poolInitFreeSize0UsingD_), + MAX_FREELIST_SIZE); + freelist_max = MAX_FREELIST_SIZE; + } + } + + if (str_pool_disable && strcasecmp(str_pool_disable, "false") ) + pool_disable = 1; + else + pool_disable = 0; + + if (known_pools_lock == NULL) { + known_pools_lock = crit_init(); + freelist_lock = crit_init(); + } + + return REQ_PROCEED; +} + + +static block_t * +_create_block(int size) +{ + block_t *newblock = NULL; + long bytes = ALIGN(size); + block_t *free_ptr, + *last_free_ptr = NULL; + + /* check freelist for large enough block first */ + + crit_enter(freelist_lock); + free_ptr = freelist; + while(free_ptr && ((free_ptr->end - free_ptr->data) < bytes)) { + last_free_ptr = free_ptr; + free_ptr = free_ptr->next; + } + + if (free_ptr) { + newblock = free_ptr; + if (last_free_ptr) + last_free_ptr->next = free_ptr->next; + else + freelist = free_ptr->next; + freelist_size -= (newblock->end - newblock->data); + crit_exit(freelist_lock); + bytes = free_ptr->end - free_ptr->data; + } + else { + pool_blocks_created++; + crit_exit(freelist_lock); + if (((newblock = (block_t *)PERM_MALLOC(sizeof(block_t))) == NULL) || + ((newblock->data = (char *)PERM_MALLOC(bytes)) == NULL)) { + ereport(LOG_CATASTROPHE, XP_GetAdminStr(DBT_poolCreateBlockOutOfMemory_)); + if (newblock) + PERM_FREE(newblock); + return NULL; + } + } + newblock->start = newblock->data; + newblock->end = newblock->data + bytes; + newblock->next = NULL; + + return newblock; +} + +/* Caller must hold lock for the pool */ +static void +_free_block(block_t *block) +{ + +#ifdef POOL_ZERO_DEBUG + memset(block->data, 0xa, block->end-block->data); +#endif /* POOL_ZERO_DEBUG */ + + if ((freelist_size + block->end - block->data) > freelist_max) { + /* Just have to delete the whole block! */ + + crit_enter(freelist_lock); + pool_blocks_freed++; + crit_exit(freelist_lock); + + PERM_FREE(block->data); +#ifdef POOL_ZERO_DEBUG + memset(block, 0xa, sizeof(block)); +#endif /* POOL_ZERO_DEBUG */ + + PERM_FREE(block); + return; + } + crit_enter(freelist_lock); + freelist_size += (block->end - block->data); + block->start = block->data; + + block->next = freelist; + freelist = block; + crit_exit(freelist_lock); +} + +/* ptr_in_pool() + * Checks to see if the given pointer is in the given pool. + * If true, returns a ptr to the block_t containing the ptr; + * otherwise returns NULL + */ +block_t * +_ptr_in_pool(pool_t *pool, void *ptr) +{ + block_t *block_ptr = NULL; + + /* try to find a block which contains this ptr */ + + if ( ((char *)ptr < (char *)pool->curr_block->end) && + ((char *)ptr >= (char *)pool->curr_block->data) ) + block_ptr = pool->curr_block; + else + for( block_ptr = pool->used_blocks; + block_ptr && + (((char *)ptr >= (char *)block_ptr->end) && + ((char *)ptr < (char *)block_ptr->data)); + block_ptr = block_ptr->next); + + return block_ptr; +} + + +NSAPI_PUBLIC pool_handle_t * +pool_create() +{ + pool_t *newpool; + + if (pool_disable) + return NULL; + + newpool = (pool_t *)PERM_MALLOC(sizeof(pool_t)); + + if (newpool) { + /* Have to initialize now, as pools get created sometimes + * before pool_init can be called... + */ + if (known_pools_lock == NULL) { + known_pools_lock = crit_init(); + freelist_lock = crit_init(); + } + + if ( (newpool->curr_block =_create_block(BLOCK_SIZE)) == NULL) { + ereport(LOG_CATASTROPHE, XP_GetAdminStr(DBT_poolCreateOutOfMemory_)); + PERM_FREE(newpool); + return NULL; + } + newpool->used_blocks = NULL; + newpool->size = 0; + newpool->next = NULL; +#ifdef POOL_LOCKING + newpool->lock = crit_init(); +#endif +#ifdef DEBUG_CACHES + newpool->time_created = time(NULL); +#endif + + /* Add to known pools list */ + crit_enter(known_pools_lock); + newpool->next = known_pools; + known_pools = newpool; + crit_exit(known_pools_lock); + } + else + ereport(LOG_CATASTROPHE, XP_GetAdminStr(DBT_poolCreateOutOfMemory_1)); + + return (pool_handle_t *)newpool; +} + +NSAPI_PUBLIC void +pool_destroy(pool_handle_t *pool_handle) +{ + pool_t *pool = (pool_t *)pool_handle; + block_t *tmp_blk; + pool_t *last, *search; + + if (pool_disable) + return; + + crit_enter(known_pools_lock); +#ifdef POOL_LOCKING + crit_enter(pool->lock); +#endif + + if (pool->curr_block) + _free_block(pool->curr_block); + + while(pool->used_blocks) { + tmp_blk = pool->used_blocks; + pool->used_blocks = pool->used_blocks->next; + _free_block(tmp_blk); + } + + /* Remove from the known pools list */ + for (last = NULL, search = known_pools; search; + last = search, search = search->next) + if (search == pool) + break; + if (search) { + if(last) + last->next = search->next; + else + known_pools = search->next; + + } + +#ifdef POOL_LOCKING + crit_exit(pool->lock); + crit_terminate(pool->lock); +#endif + crit_exit(known_pools_lock); + +#ifdef POOL_ZERO_DEBUG + memset(pool, 0xa, sizeof(pool)); +#endif /* POOL_ZERO_DEBUG */ + + PERM_FREE(pool); + + return; +} + + +NSAPI_PUBLIC void * +pool_malloc(pool_handle_t *pool_handle, size_t size) +{ + pool_t *pool = (pool_t *)pool_handle; + long reqsize, blocksize; + char *ptr; + + if (pool == NULL || pool_disable) { + return PERM_MALLOC(size); + } + +#ifdef DEBUG + if (size == 0) + return NULL; +#endif + +#ifdef POOL_LOCKING + crit_enter(pool->lock); +#endif + + reqsize = ALIGN(size); + ptr = pool->curr_block->start; + pool->curr_block->start += reqsize; + + /* does this fit into the last allocated block? */ + if (pool->curr_block->start > pool->curr_block->end) { + + /* Did not fit; time to allocate a new block */ + + pool->curr_block->start -= reqsize; /* keep structs in tact */ + + pool->curr_block->next = pool->used_blocks; + pool->used_blocks = pool->curr_block; + + /* Allocate a chunk of memory which is a multiple of BLOCK_SIZE + * bytes + */ + blocksize = ( (size + BLOCK_SIZE-1) / BLOCK_SIZE ) * BLOCK_SIZE; + if ( (pool->curr_block = _create_block(blocksize)) == NULL) { + ereport(LOG_CATASTROPHE, XP_GetAdminStr(DBT_poolMallocOutOfMemory_)); +#ifdef POOL_LOCKING + crit_exit(pool->lock); +#endif + return NULL; + } + + ptr = pool->curr_block->start; + reqsize = ALIGN(size); + pool->curr_block->start += reqsize; + } + + pool->size += reqsize; + +#ifdef POOL_LOCKING + crit_exit(pool->lock); +#endif + return ptr; +} + +void _pool_free_error() +{ + ereport(LOG_WARN, XP_GetAdminStr(DBT_freeUsedWherePermFreeShouldHaveB_)); + + return; +} + +NSAPI_PUBLIC void +pool_free(pool_handle_t *pool_handle, void *ptr) +{ + if (pool_handle == NULL || pool_disable) { + PERM_FREE(ptr); + return; + } + +#ifdef DEBUG + /* Just to be nice, check to see if the ptr was allocated in a pool. + * If not, issue a warning and do a REAL free just to make sure that + * we don't leak memory. + */ + if ( !_ptr_in_pool((pool_t *)pool_handle, ptr) ) { + _pool_free_error(); + + PERM_FREE(ptr); + } +#endif + return; +} + +NSAPI_PUBLIC void * +pool_calloc(pool_handle_t *pool_handle, size_t nelem, size_t elsize) +{ + void *ptr; + + if (pool_handle == NULL || pool_disable) + return PERM_CALLOC(elsize * nelem); + + ptr = pool_malloc(pool_handle, elsize * nelem); + if (ptr) + memset(ptr, 0, elsize * nelem); + return ptr; +} + +NSAPI_PUBLIC void * +pool_realloc(pool_handle_t *pool_handle, void *ptr, size_t size) +{ + pool_t *pool = (pool_t *)pool_handle; + void *newptr; + block_t *block_ptr; + int oldsize; + + if (pool_handle == NULL || pool_disable) + return PERM_REALLOC(ptr, size); + + if ( (newptr = pool_malloc(pool_handle, size)) == NULL) + return NULL; + + /* With our structure we don't know exactly where the end + * of the original block is. But we do know an upper bound + * which is a valid ptr. Search the outstanding blocks + * for the block which contains this ptr, and copy... + */ +#ifdef POOL_LOCKING + crit_enter(pool->lock); +#endif + + if ( !(block_ptr = _ptr_in_pool(pool, ptr)) ) { + /* User is trying to realloc nonmalloc'd space! */ + return newptr; + } + + oldsize = block_ptr->end - (char *)ptr ; + if (oldsize > size) + oldsize = size; + memmove((char *)newptr, (char *)ptr, oldsize); +#ifdef POOL_LOCKING + crit_exit(pool->lock); +#endif + + return newptr; +} + +NSAPI_PUBLIC char * +pool_strdup(pool_handle_t *pool_handle, const char *orig_str) +{ + char *new_str; + int len = strlen(orig_str); + + if (pool_handle == NULL || pool_disable) + return PERM_STRDUP(orig_str); + + new_str = (char *)pool_malloc(pool_handle, len+1); + + if (new_str) + memcpy(new_str, orig_str, len+1); + + return new_str; +} + +NSAPI_PUBLIC long +pool_space(pool_handle_t *pool_handle) +{ + pool_t *pool = (pool_t *)pool_handle; + + return pool->size; +} + +NSAPI_PUBLIC int pool_enabled() +{ +#ifndef THREAD_ANY + /* we don't have USE_NSPR defined so systhread_getdata is undef'ed */ + return 0; +#else + if (pool_disable || (getThreadMallocKey() == -1) ) + return 0; + + if (!systhread_getdata(getThreadMallocKey())) + return 0; + + return 1; +#endif +} + + +/* pool_service_debug() + * NSAPI service routine to print state information about the existing + * pools. Hopefully useful in debugging. + * + */ +#define MAX_DEBUG_LINE 1024 +#ifdef DEBUG_CACHES /* XXXrobm causes entanglement in install and admserv cgis */ +NSAPI_PUBLIC int +pool_service_debug(pblock *pb, Session *sn, Request *rq) +{ + char tmp_buf[MAX_DEBUG_LINE]; + char cbuf[DEF_CTIMEBUF]; + int len; + pool_t *pool_ptr; + block_t *block_ptr; + int pool_cnt, block_cnt; + + param_free(pblock_remove("content-type", rq->srvhdrs)); + pblock_nvinsert("content-type", "text/html", rq->srvhdrs); + + protocol_status(sn, rq, PROTOCOL_OK, NULL); + protocol_start_response(sn, rq); + + len = util_sprintf(tmp_buf, "<H2>Memory pool status report</H2>\n"); + net_write(sn->csd, tmp_buf, len); + + len = util_sprintf(tmp_buf, "Note: The 0 block in each pool is \ +the currently used block <P>\n"); + net_write(sn->csd, tmp_buf, len); + + len = util_sprintf(tmp_buf, "Freelist size: %d/%d<P>", freelist_size, + freelist_max); + net_write(sn->csd, tmp_buf, len); + + len = util_sprintf(tmp_buf, "Pool disabled: %d<P>", pool_disable); + net_write(sn->csd, tmp_buf, len); + + len = util_sprintf(tmp_buf, "Blocks created: %d<P> Blocks freed: %d", + pool_blocks_created, pool_blocks_freed); + net_write(sn->csd, tmp_buf, len); + + /* Create an HTML table */ + len = util_sprintf(tmp_buf, "<UL><TABLE BORDER=4>\n"); + net_write(sn->csd, tmp_buf, len); + len = util_sprintf(tmp_buf, "<TH>Pool #</TH>\n"); + net_write(sn->csd, tmp_buf, len); + len = util_sprintf(tmp_buf, "<TH>Pool size #</TH>\n"); + net_write(sn->csd, tmp_buf, len); +#ifdef DEBUG_CACHES + len = util_sprintf(tmp_buf, "<TH>Time Created</TH>\n"); + net_write(sn->csd, tmp_buf, len); +#endif + len = util_sprintf(tmp_buf, "<TH>Blocks</TH>\n"); + net_write(sn->csd, tmp_buf, len); + + crit_enter(known_pools_lock); + for (pool_cnt = 0, pool_ptr = known_pools; pool_ptr; + pool_ptr = pool_ptr->next, pool_cnt++) { + +#ifdef POOL_LOCKING + crit_enter(pool_ptr->lock); +#endif + len = util_snprintf(tmp_buf, MAX_DEBUG_LINE, +#ifndef DEBUG_CACHES +"<tr align=right> <td>%d</td> <td>%d</td> <td> <TABLE BORDER=2> <TH>Block #</TH><TH>data</TH><TH>curr size</TH> <TH>max size</TH>\n", +#else +"<tr align=right> <td>%d</td> <td>%d</td> <td>%s</td> <td> <TABLE BORDER=2> <TH>Block #</TH><TH>data</TH><TH>curr size</TH> <TH>max size</TH>\n", +#endif + pool_cnt, pool_space((pool_handle_t *)pool_ptr) +#ifdef DEBUG_CACHES + , util_ctime(&(pool_ptr->time_created), cbuf, DEF_CTIMEBUF)); +#else + ); +#endif + net_write(sn->csd, tmp_buf, len); + + /* Print the first block */ + len = util_snprintf(tmp_buf, MAX_DEBUG_LINE, "\ +<tr align=right> \ +<td>%d</td> \ +<td>%d</td> \ +<td>%d</td> \ +<td>%d</td> \ +</tr>\n", + 0, pool_ptr->curr_block->data, + pool_ptr->curr_block->start -pool_ptr->curr_block->data, + pool_ptr->curr_block->end - pool_ptr->curr_block->data); + + net_write(sn->csd, tmp_buf, len); + + for (block_cnt = 1, block_ptr = pool_ptr->used_blocks; block_ptr; + block_ptr = block_ptr->next, block_cnt++) { + + len = util_snprintf(tmp_buf, MAX_DEBUG_LINE, "\ +<tr align=right> \ +<td>%d</td> \ +<td>%d</td> \ +<td>%d</td> \ +<td>%d</td> \ +</tr>\n", + block_cnt, block_ptr->data, + block_ptr->start - block_ptr->data, + block_ptr->end - block_ptr->data); + + net_write(sn->csd, tmp_buf, len); + } +#ifdef POOL_LOCKING + crit_exit(pool_ptr->lock); +#endif + + len = util_snprintf(tmp_buf, MAX_DEBUG_LINE, "</TABLE></TD></TR>"); + + net_write(sn->csd, tmp_buf, len); + } + crit_exit(known_pools_lock); + + len = util_sprintf(tmp_buf, "</TABLE></UL>\n"); + net_write(sn->csd, tmp_buf, len); + + return REQ_PROCEED; + +} +#endif /* 0 */ +#endif /* MALLOC_POOLS */ + diff --git a/lib/base/rwlock.cpp b/lib/base/rwlock.cpp new file mode 100644 index 00000000..1b99e062 --- /dev/null +++ b/lib/base/rwlock.cpp @@ -0,0 +1,131 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +#include <stdlib.h> +#include "crit.h" +#include "rwlock.h" + +/* + * rwLock.c + * Implements a shared/exclusive lock package atop the + * critical section/condition variables. It allows multiple + * shared lock holders and only one exclusive lock holder + * on a lock variable. + * + * NOTE : It currently favors writers over readers and writers + * may starve readers. It is usually preferable to allow updates + * if they are not as frequent. We may have to change this if + * the common usage pattern differs from this. + */ + +typedef struct { + CRITICAL crit; /* Short term crit to synchronize lock ops */ + CONDVAR readFree; /* Indicates lock is free for readers */ + CONDVAR writeFree; /* Indicates lock is free for the writer */ + int numReaders; /* Number of read locks held */ + int write; /* Flag to indicate write lock held */ + int numWriteWaiters;/* Number of threads waiting for write lock */ +} rwLock_t; + +/* + * rwlock_init() + * Allocate and initialize the rwlock structure and return + * to the caller. + */ +RWLOCK rwlock_Init() +{ + rwLock_t *rwLockP; + + rwLockP = (rwLock_t *)PERM_MALLOC(sizeof(rwLock_t)); + rwLockP->numReaders = 0; + rwLockP->write = 0; + rwLockP->numWriteWaiters = 0; + rwLockP->crit = crit_init(); + rwLockP->readFree = condvar_init(rwLockP->crit); + rwLockP->writeFree = condvar_init(rwLockP->crit); + return((RWLOCK)rwLockP); +} + +/* + * rwlock_terminate() + * Terminate the associated condvars and critical sections + */ +void rwlock_Terminate(RWLOCK lockP) +{ + rwLock_t *rwLockP = (rwLock_t *)lockP; + + crit_terminate(rwLockP->crit); + condvar_terminate(rwLockP->readFree); + condvar_terminate(rwLockP->writeFree); + PERM_FREE(rwLockP); +} + +/* + * rwlock_ReadLock -- Obtain a shared lock. The caller would + * block if there are writers or writeWaiters. + */ +void rwlock_ReadLock(RWLOCK lockP) +{ + rwLock_t *rwLockP = (rwLock_t *)lockP; + + crit_enter(rwLockP->crit); + while (rwLockP->write || rwLockP->numWriteWaiters != 0) + condvar_wait(rwLockP->readFree); + rwLockP->numReaders++; + crit_exit(rwLockP->crit); +} + +/* + * rwlock_writeLock -- Obtain an exclusive lock. The caller would + * block if there are other readers or a writer. + */ +void rwlock_WriteLock(RWLOCK lockP) +{ + rwLock_t *rwLockP = (rwLock_t *)lockP; + + crit_enter(rwLockP->crit); + rwLockP->numWriteWaiters++; + while (rwLockP->numReaders != 0 || rwLockP->write) + condvar_wait(rwLockP->writeFree); + rwLockP->numWriteWaiters--; + rwLockP->write = 1; + crit_exit(rwLockP->crit); +} + +/* + * rw_Unlock -- Releases the lock. + */ +void rwlock_Unlock(RWLOCK lockP) +{ + rwLock_t *rwLockP = (rwLock_t *)lockP; + + crit_enter(rwLockP->crit); + if (rwLockP->write) + rwLockP->write = 0; + else + rwLockP->numReaders--; + if (rwLockP->numReaders == 0) + if (rwLockP->numWriteWaiters != 0) + condvar_notify(rwLockP->writeFree); + else + condvar_notifyAll(rwLockP->readFree); + crit_exit(rwLockP->crit); +} + +/* + * rwlock_DemoteLock -- Change an exclusive lock on the given lock + * variable into a shared lock. + */ +void rwlock_DemoteLock(RWLOCK lockP) +{ + rwLock_t *rwLockP = (rwLock_t *)lockP; + + crit_enter(rwLockP->crit); + rwLockP->numReaders = 1; + rwLockP->write = 0; + if (rwLockP->numWriteWaiters == 0) + condvar_notifyAll(rwLockP->readFree); + crit_exit(rwLockP->crit); +} diff --git a/lib/base/shexp.cpp b/lib/base/shexp.cpp new file mode 100644 index 00000000..8cb2aae4 --- /dev/null +++ b/lib/base/shexp.cpp @@ -0,0 +1,290 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * shexp.c: shell-like wildcard match routines + * + * + * See shexp.h for public documentation. + * + * Rob McCool + * + */ + +#include "shexp.h" +#include <ctype.h> /* isalpha, tolower */ + + +/* ----------------------------- shexp_valid ------------------------------ */ + + +int valid_subexp(char *exp, char stop) +{ + register int x,y,t; + int nsc,np,tld; + + x=0;nsc=0;tld=0; + + while(exp[x] && (exp[x] != stop)) { + switch(exp[x]) { + case '~': + if(tld) return INVALID_SXP; + else ++tld; + case '*': + case '?': + case '^': + case '$': + ++nsc; + break; + case '[': + ++nsc; + if((!exp[++x]) || (exp[x] == ']')) + return INVALID_SXP; + for(++x;exp[x] && (exp[x] != ']');++x) + if(exp[x] == '\\') + if(!exp[++x]) + return INVALID_SXP; + if(!exp[x]) + return INVALID_SXP; + break; + case '(': + ++nsc; + while(1) { + if(exp[++x] == ')') + return INVALID_SXP; + for(y=x;(exp[y]) && (exp[y] != '|') && (exp[y] != ')');++y) + if(exp[y] == '\\') + if(!exp[++y]) + return INVALID_SXP; + if(!exp[y]) + return INVALID_SXP; + t = valid_subexp(&exp[x],exp[y]); + if(t == INVALID_SXP) + return INVALID_SXP; + x+=t; + if(exp[x] == ')') { + break; + } + } + break; + case ')': + case ']': + return INVALID_SXP; + case '\\': + if(!exp[++x]) + return INVALID_SXP; + default: + break; + } + ++x; + } + if((!stop) && (!nsc)) + return NON_SXP; + return ((exp[x] == stop) ? x : INVALID_SXP); +} + +NSAPI_PUBLIC int shexp_valid(char *exp) { + int x; + + x = valid_subexp(exp, '\0'); + return (x < 0 ? x : VALID_SXP); +} + + +/* ----------------------------- shexp_match ----------------------------- */ + + +#define MATCH 0 +#define NOMATCH 1 +#define ABORTED -1 + +int _shexp_match(char *str, char *exp); + +int handle_union(char *str, char *exp) +{ + char *e2 = (char *) MALLOC(sizeof(char)*strlen(exp)); + register int t,p2,p1 = 1; + int cp; + + while(1) { + for(cp=1;exp[cp] != ')';cp++) + if(exp[cp] == '\\') + ++cp; + for(p2 = 0;(exp[p1] != '|') && (p1 != cp);p1++,p2++) { + if(exp[p1] == '\\') + e2[p2++] = exp[p1++]; + e2[p2] = exp[p1]; + } + for(t=cp+1;(e2[p2] = exp[t]);++t,++p2); + if(_shexp_match(str,e2) == MATCH) { + FREE(e2); + return MATCH; + } + if(p1 == cp) { + FREE(e2); + return NOMATCH; + } + else ++p1; + } +} + + +int _shexp_match(char *str, char *exp) +{ + register int x,y; + int ret,neg; + + ret = 0; + for(x=0,y=0;exp[y];++y,++x) { + if((!str[x]) && (exp[y] != '(') && (exp[y] != '$') && (exp[y] != '*')) + ret = ABORTED; + else { + switch(exp[y]) { + case '$': + if( (str[x]) ) + ret = NOMATCH; + else + --x; /* we don't want loop to increment x */ + break; + case '*': + while(exp[++y] == '*'); + if(!exp[y]) + return MATCH; + while(str[x]) { + switch(_shexp_match(&str[x++],&exp[y])) { + case NOMATCH: + continue; + case ABORTED: + ret = ABORTED; + break; + default: + return MATCH; + } + break; + } + if((exp[y] == '$') && (exp[y+1] == '\0') && (!str[x])) + return MATCH; + else + ret = ABORTED; + break; + case '[': + if((neg = ((exp[++y] == '^') && (exp[y+1] != ']')))) + ++y; + + if((isalnum(exp[y])) && (exp[y+1] == '-') && + (isalnum(exp[y+2])) && (exp[y+3] == ']')) + { + int start = exp[y], end = exp[y+2]; + + /* Droolproofing for pinheads not included */ + if(neg ^ ((str[x] < start) || (str[x] > end))) { + ret = NOMATCH; + break; + } + y+=3; + } + else { + int matched; + + for(matched=0;exp[y] != ']';y++) + matched |= (str[x] == exp[y]); + if(neg ^ (!matched)) + ret = NOMATCH; + } + break; + case '(': + return handle_union(&str[x],&exp[y]); + break; + case '?': + break; + case '\\': + ++y; + default: +#ifdef XP_UNIX + if(str[x] != exp[y]) +#else /* XP_WIN32 */ + if(strnicmp(str + x, exp + y, 1)) +#endif /* XP_WIN32 */ + ret = NOMATCH; + break; + } + } + if(ret) + break; + } + return (ret ? ret : (str[x] ? NOMATCH : MATCH)); +} + +NSAPI_PUBLIC int shexp_match(char *str, char *xp) { + register int x; + char *exp = STRDUP(xp); + + for(x=strlen(exp)-1;x;--x) { + if((exp[x] == '~') && (exp[x-1] != '\\')) { + exp[x] = '\0'; + if(_shexp_match(str,&exp[++x]) == MATCH) + goto punt; + break; + } + } + if(_shexp_match(str,exp) == MATCH) { + FREE(exp); + return 0; + } + + punt: + FREE(exp); + return 1; +} + + +/* ------------------------------ shexp_cmp ------------------------------- */ + + +NSAPI_PUBLIC int shexp_cmp(char *str, char *exp) +{ + switch(shexp_valid(exp)) { + case INVALID_SXP: + return -1; + case NON_SXP: +#ifdef XP_UNIX + return (strcmp(exp,str) ? 1 : 0); +#else /* XP_WIN32 */ + return (stricmp(exp,str) ? 1 : 0); +#endif /* XP_WIN32 */ + default: + return shexp_match(str, exp); + } +} + + +/* ---------------------------- shexp_casecmp ----------------------------- */ + + +NSAPI_PUBLIC int shexp_casecmp(char *str, char *exp) +{ + char *lstr = STRDUP(str), *lexp = STRDUP(exp), *t; + int ret; + + for(t = lstr; *t; t++) + if(isalpha(*t)) *t = tolower(*t); + for(t = lexp; *t; t++) + if(isalpha(*t)) *t = tolower(*t); + + switch(shexp_valid(lexp)) { + case INVALID_SXP: + ret = -1; + break; + case NON_SXP: + ret = (strcmp(lexp, lstr) ? 1 : 0); + break; + default: + ret = shexp_match(lstr, lexp); + } + FREE(lstr); + FREE(lexp); + return ret; +} + diff --git a/lib/base/shmem.cpp b/lib/base/shmem.cpp new file mode 100644 index 00000000..1ddd76d3 --- /dev/null +++ b/lib/base/shmem.cpp @@ -0,0 +1,127 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * shmem.h: Portable abstraction for memory shared among a server's workers + * + * Rob McCool + */ + + +#include "shmem.h" + +#if defined (SHMEM_UNIX_MMAP) + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <private/pprio.h> /* for nspr20 binary release */ + +NSPR_BEGIN_EXTERN_C +#include <sys/mman.h> +NSPR_END_EXTERN_C + +NSAPI_PUBLIC shmem_s *shmem_alloc(char *name, int size, int expose) +{ + shmem_s *ret = (shmem_s *) PERM_MALLOC(sizeof(shmem_s)); + char *growme; + + if( (ret->fd = PR_Open(name, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 0666)) == NULL) { + PERM_FREE(ret); + return NULL; + } + growme = (char *) PERM_MALLOC(size); + ZERO(growme, size); + if(PR_Write(ret->fd, (char *)growme, size) < 0) { + PR_Close(ret->fd); + PERM_FREE(growme); + PERM_FREE(ret); + return NULL; + } + PERM_FREE(growme); + PR_Seek(ret->fd, 0, PR_SEEK_SET); + if( (ret->data = (char *)mmap(NULL, size, PROT_READ | PROT_WRITE, + SHMEM_MMAP_FLAGS, PR_FileDesc2NativeHandle(ret->fd), 0)) == (caddr_t) -1) + { + PR_Close(ret->fd); + PERM_FREE(ret); + return NULL; + } + if(!expose) { + ret->name = NULL; + unlink(name); + } + else + ret->name = STRDUP(name); + ret->size = size; + return ret; +} + + +NSAPI_PUBLIC void shmem_free(shmem_s *region) +{ + if(region->name) { + unlink(region->name); + PERM_FREE(region->name); + } + munmap((char *)region->data, region->size); /* CLEARLY, C++ SUCKS */ + PR_Close(region->fd); + PERM_FREE(region); +} + +#elif defined (SHMEM_WIN32_MMAP) + +#define PAGE_SIZE (1024*8) +#define ALIGN(x) ( (x+PAGE_SIZE-1) & (~(PAGE_SIZE-1)) ) +NSAPI_PUBLIC shmem_s *shmem_alloc(char *name, int size, int expose) +{ + shmem_s *ret = (shmem_s *) PERM_MALLOC(sizeof(shmem_s)); + HANDLE fHandle; + + ret->fd = 0; /* not used on NT */ + + size = ALIGN(size); + if( !(ret->fdmap = CreateFileMapping( + (HANDLE)0xffffffff, + NULL, + PAGE_READWRITE, + 0, + size, + name)) ) + { + int err = GetLastError(); + PERM_FREE(ret); + return NULL; + } + if( !(ret->data = (char *)MapViewOfFile ( + ret->fdmap, + FILE_MAP_ALL_ACCESS, + 0, + 0, + 0)) ) + { + CloseHandle(ret->fdmap); + PERM_FREE(ret); + return NULL; + } + ret->size = size; + ret->name = NULL; + + return ret; +} + + +NSAPI_PUBLIC void shmem_free(shmem_s *region) +{ + if(region->name) { + DeleteFile(region->name); + PERM_FREE(region->name); + } + UnmapViewOfFile(region->data); + CloseHandle(region->fdmap); + PERM_FREE(region); +} + +#endif /* SHMEM_WIN32_MMAP */ diff --git a/lib/base/system.cpp b/lib/base/system.cpp new file mode 100644 index 00000000..e58538b4 --- /dev/null +++ b/lib/base/system.cpp @@ -0,0 +1,264 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * system.c: A grab bag of system-level abstractions + * + * Many authors + */ + +#include "netsite.h" +#include "base/nsassert.h" +#include "base/ereport.h" + +#ifdef XP_WIN32 +#include <windows.h> +static char *version = "Netscape Server/2.0"; +#endif + +#include "base/systems.h" /* find out if we have malloc pools */ + +static int thread_malloc_key = -1; + +#if defined(MALLOC_POOLS) && defined(MCC_HTTPD) && defined(THREAD_ANY) +#include "base/pool.h" +#include "base/systhr.h" + +#define MALLOC_KEY \ + ((pool_handle_t *)(thread_malloc_key != -1 ? systhread_getdata(thread_malloc_key) : NULL)) + +#endif + + +#ifdef MCC_DEBUG +#define DEBUG_MALLOC +#endif + +#ifdef DEBUG_MALLOC + +/* The debug malloc routines provide several functions: + * + * - detect allocated memory overflow/underflow + * - detect multiple frees + * - intentionally clobbers malloc'd buffers + * - intentionally clobbers freed buffers + */ +#define DEBUG_MAGIC 0x12345678 +#define DEBUG_MARGIN 32 +#define DEBUG_MARGIN_CHAR '*' +#define DEBUG_MALLOC_CHAR '.' +#define DEBUG_FREE_CHAR 'X' +#endif /* DEBUG_MALLOC */ + +/* On NT, the server version string is not statically encoded based + * upon a product compile define but dynamically set by the server + * exe at startup. + */ + +NSAPI_PUBLIC char *system_version() +{ +#ifdef XP_WIN32 + return version; +#else /* XP_UNIX */ + return MAGNUS_VERSION_STRING; +#endif /* XP_UNIX */ +} + +NSAPI_PUBLIC void system_version_set(char *server_version) +{ +#ifdef XP_WIN32 + version = PERM_STRDUP(server_version); +#endif +} + + +NSAPI_PUBLIC void *system_malloc(int size) +{ +#if defined(MALLOC_POOLS) && defined(MCC_HTTPD) && defined(THREAD_ANY) + return pool_malloc(MALLOC_KEY, size); +#else + return malloc(size); +#endif +} + + +NSAPI_PUBLIC void *system_calloc(int size) +{ + void *ret; +#if defined(MALLOC_POOLS) && defined(MCC_HTTPD) && defined(THREAD_ANY) + ret = pool_malloc(MALLOC_KEY, size); +#else + ret = malloc(size); +#endif + if(ret) + ZERO(ret, size); + return ret; +} + + +NSAPI_PUBLIC void *system_realloc(void *ptr, int size) +{ +#if defined(MALLOC_POOLS) && defined(MCC_HTTPD) && defined(THREAD_ANY) + return pool_realloc(MALLOC_KEY, ptr, size); +#else + return realloc(ptr, size); +#endif +} + + +NSAPI_PUBLIC void system_free(void *ptr) +{ +#if defined(MALLOC_POOLS) && defined(MCC_HTTPD) && defined(THREAD_ANY) + pool_free(MALLOC_KEY, ptr); +#else + NS_ASSERT(ptr); + free(ptr); +#endif +} + +NSAPI_PUBLIC char *system_strdup(const char *ptr) +{ + NS_ASSERT(ptr); +#if defined(MALLOC_POOLS) && defined(MCC_HTTPD) && defined(THREAD_ANY) + return pool_strdup(MALLOC_KEY, ptr); +#else + return strdup(ptr); +#endif +} + + +NSAPI_PUBLIC void *system_malloc_perm(int size) +{ +#ifndef DEBUG_MALLOC + return malloc(size); +#else + char *ptr = (char *)malloc(size + 2*DEBUG_MARGIN+2*sizeof(int)); + char *real_ptr; + int *magic; + int *length; + + magic = (int *)ptr; + *magic = DEBUG_MAGIC; + ptr += sizeof(int); + length = (int *)ptr; + *length = size; + ptr += sizeof(int); + memset(ptr, DEBUG_MARGIN_CHAR, DEBUG_MARGIN); + ptr += DEBUG_MARGIN; + memset(ptr, DEBUG_MALLOC_CHAR, size); + real_ptr = ptr; + ptr += size; + memset(ptr, DEBUG_MARGIN_CHAR, DEBUG_MARGIN); + + return real_ptr; +#endif +} + +NSAPI_PUBLIC void *system_calloc_perm(int size) +{ + void *ret = system_malloc_perm(size); + if(ret) + ZERO(ret, size); + return ret; +} + +NSAPI_PUBLIC void *system_realloc_perm(void *ptr, int size) +{ +#ifndef DEBUG_MALLOC + return realloc(ptr, size); +#else + int *magic, *length; + char *baseptr; + char *cptr; + + cptr = (char *)ptr - DEBUG_MARGIN - 2 * sizeof(int); + magic = (int *)cptr; + if (*magic == DEBUG_MAGIC) { + cptr += sizeof(int); + length = (int *)cptr; + if (*length < size) { + char *newptr = (char *)system_malloc_perm(size); + memcpy(newptr, ptr, *length); + system_free_perm(ptr); + + return newptr; + }else { + return ptr; + } + } else { + ereport(LOG_WARN, "realloc: attempt to realloc to smaller size"); + return realloc(ptr, size); + } + +#endif +} + +NSAPI_PUBLIC void system_free_perm(void *ptr) +{ +#ifdef DEBUG_MALLOC + int *length, *magic; + char *baseptr, *cptr; + int index; + + NS_ASSERT(ptr); + + cptr = baseptr = ((char *)ptr) - DEBUG_MARGIN - 2*sizeof(int); + + magic = (int *)cptr; + if (*magic == DEBUG_MAGIC) { + cptr += sizeof(int); + + length = (int *)cptr; + + cptr += sizeof(int); + for (index=0; index<DEBUG_MARGIN; index++) + if (cptr[index] != DEBUG_MARGIN_CHAR) { + ereport(LOG_CATASTROPHE, "free: corrupt memory (prebounds overwrite)"); + break; + } + + cptr += DEBUG_MARGIN + *length; + for (index=0; index<DEBUG_MARGIN; index++) + if (cptr[index] != DEBUG_MARGIN_CHAR) { + ereport(LOG_CATASTROPHE, "free: corrupt memory (prebounds overwrite)"); + break; + } + + memset(baseptr, DEBUG_FREE_CHAR, *length + 2*DEBUG_MARGIN+sizeof(int)); + } else { + ereport(LOG_CATASTROPHE, "free: freeing unallocated memory"); + } + free(baseptr); +#else + free(ptr); +#endif +} + +NSAPI_PUBLIC char *system_strdup_perm(const char *ptr) +{ +#ifndef DEBUG_MALLOC + NS_ASSERT(ptr); + return strdup(ptr); +#else + int len = strlen(ptr); + char *nptr = (char *)system_malloc_perm(len+1); + memcpy(nptr, ptr, len); + nptr[len] = '\0'; + return nptr; +#endif +} + +NSAPI_PUBLIC int +getThreadMallocKey(void) +{ + return thread_malloc_key; +} + +void +setThreadMallocKey(int key) +{ + thread_malloc_key = key; +} + diff --git a/lib/base/systhr.cpp b/lib/base/systhr.cpp new file mode 100644 index 00000000..ac29121a --- /dev/null +++ b/lib/base/systhr.cpp @@ -0,0 +1,256 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * systhr.c: Abstracted threading mechanisms + * + * Rob McCool + */ + +#include "systhr.h" +#include "ereport.h" + +#define USE_NSPR +#ifdef USE_NSPR +#include "nspr.h" +#include "private/prpriv.h" +extern "C" { +int32 PR_GetSysfdTableMax(void); +int32 PR_SetSysfdTableSize(int table_size); +} +#endif +#include "systems.h" + +#ifdef THREAD_WIN32 +#include <process.h> + +typedef struct { + HANDLE hand; + DWORD id; +} sys_thread_s; + +#endif + + + +#if defined (USE_NSPR) + + +#define DEFAULT_STACKSIZE (64*1024) + +static unsigned long _systhr_stacksize = DEFAULT_STACKSIZE; + +NSAPI_PUBLIC +void systhread_set_default_stacksize(unsigned long size) +{ + _systhr_stacksize = size; +} + +NSPR_BEGIN_EXTERN_C + +NSAPI_PUBLIC SYS_THREAD +#ifdef UnixWare /* for ANSI C++ standard, see base/systrh.h */ +systhread_start(int prio, int stksz, ArgFn_systhread_start fn, void *arg) +#else +systhread_start(int prio, int stksz, void (*fn)(void *), void *arg) +#endif +{ +#if (defined(Linux) || defined(SNI) || defined(UnixWare)) && !defined(USE_PTHREADS) + prio /= 8; /* quick and dirty fix for user thread priority scale problem */ + if (prio > 3) prio = 3; +#endif + + PRThread *ret = PR_CreateThread(PR_USER_THREAD, (void (*)(void *))fn, + (void *)arg, (PRThreadPriority)prio, + PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, + stksz ? stksz : _systhr_stacksize); + return (void *) ret; +} + +NSPR_END_EXTERN_C + + +NSAPI_PUBLIC SYS_THREAD systhread_current(void) +{ + return PR_GetCurrentThread(); +} + +NSAPI_PUBLIC void systhread_yield(void) +{ + /* PR_Yield(); */ + PR_Sleep(PR_INTERVAL_NO_WAIT); +} + + +NSAPI_PUBLIC void systhread_timerset(int usec) +{ + /* This is an interesting problem. If you ever do turn on interrupts + * on the server, you're in for lots of fun with NSPR Threads + PR_StartEvents(usec); */ +} + + +NSAPI_PUBLIC +SYS_THREAD systhread_attach(void) +{ + PRThread *ret; + ret = PR_AttachThread(PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL); + + return (void *) ret; +} + +NSAPI_PUBLIC +void systhread_detach(SYS_THREAD thr) +{ + /* XXXMB - this is not correct! */ + PR_DetachThread(); +} + +NSAPI_PUBLIC void systhread_terminate(SYS_THREAD thr) +{ + + /* Should never be here. PR_DestroyThread is no + * longer used. */ + PR_ASSERT(0); + + /* PR_DestroyThread((PRThread *) thr); */ +} + +NSAPI_PUBLIC void systhread_sleep(int milliseconds) +{ + PR_Sleep(milliseconds); +} + +NSAPI_PUBLIC void systhread_init(char *name) +{ + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256); +#ifdef XP_UNIX + /* XXXrobm allocate all the fd's we can... */ + PR_SetSysfdTableSize(PR_GetSysfdTableMax()); +#endif +} + + +NSAPI_PUBLIC int systhread_newkey() +{ + uintn newkey; + + PR_NewThreadPrivateIndex(&newkey, NULL); + return (newkey); +} + +NSAPI_PUBLIC void *systhread_getdata(int key) +{ + return PR_GetThreadPrivate(key); +} + +NSAPI_PUBLIC void systhread_setdata(int key, void *data) +{ + PR_SetThreadPrivate(key, data); +} + +/* + * Drag in the Java code, so our dynamic library full of it works + * i.e. force these symbols to load. + */ +NSAPI_PUBLIC void systhread_dummy(void) +{ + +#ifndef NSPR20 + /* nspr/gc.c */ + PR_InitGC(0,0); + /* nspr/prsystem.c */ + PR_GetSystemInfo(PR_SI_SYSNAME, 0, 0); + /* nspr/linker.c */ + PR_GetLibName(0, 0); + /* nspr/file.c */ + PR_Mkdir(0, 0); + /* nspr/prnetdb.c */ + PR_gethostbyname(0, 0, 0, 0, 0); + /* nspr/longlong.c */ + LL_TO_S(LL_ZERO, 0, NULL, 0); +#endif /* NSPR20 */ +} + +#elif defined(THREAD_WIN32) + +#include <nspr/prthread.h> +#define DEFAULT_STACKSIZE 262144 + +NSPR_BEGIN_EXTERN_C + +NSAPI_PUBLIC +SYS_THREAD systhread_start(int prio, int stksz, void (*fn)(void *), void *arg) +{ + sys_thread_s *ret = (sys_thread_s *) MALLOC(sizeof(sys_thread_s)); + + if ((ret->hand = (HANDLE)_beginthreadex(NULL, stksz, (unsigned (__stdcall *)(void *))fn, + arg, 0, &ret->id)) == 0) { + FREE(ret); + return NULL; + } + return (void *)ret; +} + +NSPR_END_EXTERN_C + +NSAPI_PUBLIC SYS_THREAD systhread_current(void) +{ + /* XXXrobm this is busted.... */ + return GetCurrentThread(); +} + +NSAPI_PUBLIC void systhread_timerset(int usec) +{ +} + +NSAPI_PUBLIC SYS_THREAD systhread_attach(void) +{ + return NULL; +} + +NSAPI_PUBLIC void systhread_yield(void) +{ + systhread_sleep(0); +} + +NSAPI_PUBLIC void systhread_terminate(SYS_THREAD thr) +{ + TerminateThread(((sys_thread_s *)thr)->hand, 0); +} + + +NSAPI_PUBLIC void systhread_sleep(int milliseconds) +{ + /* XXXrobm there must be a better way to do this */ + HANDLE sem = CreateSemaphore(NULL, 1, 4, "sleeper"); + WaitForSingleObject(sem, INFINITE); + WaitForSingleObject(sem, milliseconds); + CloseHandle(sem); +} + +NSAPI_PUBLIC void systhread_init(char *name) +{ + PR_Init(PR_USER_THREAD, 1, 0); +} + + +NSAPI_PUBLIC int systhread_newkey() +{ + return TlsAlloc(); +} + +NSAPI_PUBLIC void *systhread_getdata(int key) +{ + return (void *)TlsGetValue(key); +} + +NSAPI_PUBLIC void systhread_setdata(int key, void *data) +{ + TlsSetValue(key, data); +} + +#endif + diff --git a/lib/base/util.cpp b/lib/base/util.cpp new file mode 100644 index 00000000..55d6ca56 --- /dev/null +++ b/lib/base/util.cpp @@ -0,0 +1,1449 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * util.c: A hodge podge of utility functions and standard functions which + * are unavailable on certain systems + * + * Rob McCool + */ + +#ifdef XP_UNIX +#include <sys/types.h> +#include <sys/wait.h> +#include <stdlib.h> +#include "prthread.h" +#endif /* XP_UNIX */ + +#include "base/util.h" + +#include "base/dbtbase.h" +#include "base/ereport.h" + + +#ifdef XP_UNIX +#include <sys/types.h> +#endif /* WIN32 */ + +/* ----------------------------- util_getline ----------------------------- */ + +#define LF 10 +#define CR 13 + +NSAPI_PUBLIC int util_getline(filebuf_t *buf, int lineno, int maxlen, char *l) { + int i, x; + + x = 0; + while(1) { + i = filebuf_getc(buf); + switch(i) { + case IO_EOF: + l[x] = '\0'; + return 1; + case LF: + if(x && (l[x-1] == '\\')) { + --x; + continue; + } + l[x] = '\0'; + return 0; + case IO_ERROR: + util_sprintf(l, "I/O error reading file at line %d", lineno); + return -1; + case CR: + continue; + default: + l[x] = (char) i; + if(++x == maxlen) { + util_sprintf(l, "line %d is too long", lineno); + return -1; + } + break; + } + } +} + + +/* ---------------------------- util_can_exec ----------------------------- */ + +#ifdef XP_UNIX +NSAPI_PUBLIC int util_can_exec(struct stat *fi, uid_t uid, gid_t gid) +{ + if(!uid) + return 1; + if((fi->st_mode & S_IXOTH) || + ((gid == fi->st_gid) && (fi->st_mode & S_IXGRP)) || + ((uid == fi->st_uid) && (fi->st_mode & S_IXUSR))) + return 1; + return 0; +} +#endif /* XP_UNIX */ + + +/* --------------------------- util_env_create ---------------------------- */ + + +NSAPI_PUBLIC char **util_env_create(char **env, int n, int *pos) +{ + int x; + + if(!env) { + *pos = 0; + return (char **) MALLOC((n + 1)*sizeof(char *)); + } + else { + for(x = 0; (env[x]); x++); + env = (char **) REALLOC(env, (n + x + 1)*(sizeof(char *))); + *pos = x; + return env; + } +} + + +/* ---------------------------- util_env_free ----------------------------- */ + + +NSAPI_PUBLIC void util_env_free(char **env) +{ + register char **ep = env; + + for(ep = env; *ep; ep++) + FREE(*ep); + FREE(env); +} + +/* ----------------------------- util_env_str ----------------------------- */ + + +NSAPI_PUBLIC char *util_env_str(char *name, char *value) { + char *t,*tp; + + t = (char *) MALLOC(strlen(name)+strlen(value)+2); /* 2: '=' and '\0' */ + + for(tp=t; (*tp = *name); tp++,name++); + for(*tp++ = '='; (*tp = *value); tp++,value++); + return t; +} + + +/* --------------------------- util_env_replace --------------------------- */ + + +NSAPI_PUBLIC void util_env_replace(char **env, char *name, char *value) +{ + int x, y, z; + char *i; + + for(x = 0; env[x]; x++) { + i = strchr(env[x], '='); + *i = '\0'; + if(!strcmp(env[x], name)) { + y = strlen(env[x]); + z = strlen(value); + + env[x] = (char *) REALLOC(env[x], y + z + 2); + util_sprintf(&env[x][y], "=%s", value); + return; + } + *i = '='; + } +} + + +/* ---------------------------- util_env_find ----------------------------- */ + + +NSAPI_PUBLIC char *util_env_find(char **env, char *name) +{ + char *i; + int x, r; + + for(x = 0; env[x]; x++) { + i = strchr(env[x], '='); + *i = '\0'; + r = !strcmp(env[x], name); + *i = '='; + if(r) + return i + 1; + } + return NULL; +} + + +/* ---------------------------- util_env_copy ----------------------------- */ + + +NSAPI_PUBLIC char **util_env_copy(char **src, char **dst) +{ + char **src_ptr; + int src_cnt; + int index; + + if (!src) + return NULL; + + for (src_cnt = 0, src_ptr = src; *src_ptr; src_ptr++, src_cnt++); + + if (!src_cnt) + return NULL; + + dst = util_env_create(dst, src_cnt, &index); + + for (src_ptr = src, index=0; *src_ptr; index++, src_ptr++) + dst[index] = STRDUP(*src_ptr); + dst[index] = NULL; + + return dst; +} + +/* ---------------------------- util_hostname ----------------------------- */ + + +/* + * MOVED TO NET.C TO AVOID INTERDEPENDENCIES + */ + + +/* --------------------------- util_chdir2path ---------------------------- */ + + +NSAPI_PUBLIC int util_chdir2path(char *path) +{ + /* use FILE_PATHSEP to accomodate WIN32 */ + char *t = strrchr(path, FILE_PATHSEP); + int ret; + + if(!t) + return -1; + + *t = '\0'; +#ifdef XP_UNIX + ret = chdir(path); +#else /* WIN32 */ + ret = SetCurrentDirectory(path); +#endif /* XP_UNIX */ + + /* use FILE_PATHSEP instead of chdir to accomodate WIN32 */ + *t = FILE_PATHSEP; + + return ret; +} + + +/* --------------------------- util_is_mozilla ---------------------------- */ + + +NSAPI_PUBLIC int util_is_mozilla(char *ua, char *major, char *minor) +{ + if((!ua) || strncasecmp(ua, "Mozilla/", 8)) + return 0; + + /* Major version. I punted on supporting versions like 10.0 */ + if(ua[8] > major[0]) + return 1; + else if((ua[8] < major[0]) || (ua[9] != '.')) + return 0; + + /* Minor version. Support version numbers like 0.96 */ + if(ua[10] < minor[0]) + return 0; + else if((ua[10] > minor[0]) || (!minor[1])) + return 1; + + if((!isdigit(ua[11])) || (ua[11] < minor[1])) + return 0; + else + return 1; +} + + +/* ----------------------------- util_is_url ------------------------------ */ + + +#include <ctype.h> /* isalpha */ + +NSAPI_PUBLIC int util_is_url(char *url) +{ + char *t = url; + + while(*t) { + if(*t == ':') + return 1; + if(!isalpha(*t)) + return 0; + ++t; + } + return 0; +} + + +/* --------------------------- util_later_than ---------------------------- */ + + +int _mstr2num(char *str) { + if(!strcasecmp(str, "Jan")) return 0; + if(!strcasecmp(str, "Feb")) return 1; + if(!strcasecmp(str, "Mar")) return 2; + if(!strcasecmp(str, "Apr")) return 3; + if(!strcasecmp(str, "May")) return 4; + if(!strcasecmp(str, "Jun")) return 5; + if(!strcasecmp(str, "Jul")) return 6; + if(!strcasecmp(str, "Aug")) return 7; + if(!strcasecmp(str, "Sep")) return 8; + if(!strcasecmp(str, "Oct")) return 9; + if(!strcasecmp(str, "Nov")) return 10; + if(!strcasecmp(str, "Dec")) return 11; + return -1; +} + +int _time_compare(struct tm *lms, char *ims, int later_than_op) +{ + int y = 0, mnum = 0, d = 0, h = 0, m = 0, s = 0, x; + char t[128]; + + /* Supported formats start with weekday (which we don't care about) */ + /* The sizeof(t) is to avoid buffer overflow with t */ + if((!(ims = strchr(ims,' '))) || (strlen(ims) > (sizeof(t) - 2))) + return 0; + + while(*ims && isspace(*ims)) ++ims; + if((!(*ims)) || (strlen(ims) < 2)) + return 0; + + /* Standard HTTP (RFC 850) starts with dd-mon-yy */ + if(ims[2] == '-') { + sscanf(ims, "%s %d:%d:%d", t, &h, &m, &s); + if(strlen(t) < 6) + return 0; + t[2] = '\0'; + t[6] = '\0'; + d = atoi(t); + mnum = _mstr2num(&t[3]); + x = atoi(&t[7]); + /* Postpone wraparound until 2070 */ + y = x + (x < 70 ? 2000 : 1900); + } + /* The ctime format starts with a month name */ + else if(isalpha(*ims)) { + sscanf(ims,"%s %d %d:%d:%d %*s %d", t, &d, &h, &m, &s, &y); + mnum = _mstr2num(t); + } + /* RFC 822 */ + else { + sscanf(ims, "%d %s %d %d:%d:%d", &d, t, &y, &h, &m, &s); + mnum = _mstr2num(t); + } + + if (later_than_op) { + if( (x = (1900 + lms->tm_year) - y) ) + return x < 0; + + if(mnum == -1) + return 0; + + /* XXXMB - this will fail if you check if december 31 1996 is later + * than january 1 1997 + */ + if((x = lms->tm_mon - mnum) || (x = lms->tm_mday - d) || + (x = lms->tm_hour - h) || (x = lms->tm_min - m) || + (x = lms->tm_sec - s)) + return x < 0; + + return 1; + } + else { + return (mnum != -1 && + 1900 + lms->tm_year == y && + lms->tm_mon == mnum && + lms->tm_mday == d && + lms->tm_hour == h && + lms->tm_min == m && + lms->tm_sec == s); + } +} + + +/* Returns 0 if lms later than ims + * Returns 1 if equal + * Returns 1 if ims later than lms + */ +NSAPI_PUBLIC int util_later_than(struct tm *lms, char *ims) +{ + return _time_compare(lms, ims, 1); +} + + +NSAPI_PUBLIC int util_time_equal(struct tm *lms, char *ims) +{ + return _time_compare(lms, ims, 0); +} + +/* util_str_time_equal() + * + * Function to compare if two time strings are equal + * + * Acceptible date formats: + * Saturday, 17-Feb-96 19:41:34 GMT <RFC850> + * Sat, 17 Mar 1996 19:41:34 GMT <RFC1123> + * + * Argument t1 MUST be RFC1123 format. + * + * Note- it is not the intention of this routine to *always* match + * There are cases where we would return != when the strings might + * be equal (especially with case). The converse should not be true. + * + * Return 0 if equal, -1 if not equal. + */ +#define MINIMUM_LENGTH 18 +#define RFC1123_DAY 5 +#define RFC1123_MONTH 8 +#define RFC1123_YEAR 12 +#define RFC1123_HOUR 17 +#define RFC1123_MINUTE 20 +#define RFC1123_SECOND 23 +NSAPI_PUBLIC int util_str_time_equal(char *t1, char *t2) +{ + int index; + + /* skip over leading whitespace... */ + while(*t1 && isspace(*t1)) ++t1; + while(*t2 && isspace(*t2)) ++t2; + + /* Check weekday */ + if ( (t1[0] != t2[0]) || (t1[1] != t2[1]) ) + return -1; + + /* Skip to date */ + while(*t2 && !isspace(*t2)) ++t2; + t2++; + + /* skip if not strings not long enough */ + if ( (strlen(t1) < MINIMUM_LENGTH) || (strlen(t2) < MINIMUM_LENGTH) ) + return -1; + + if ( (t1[RFC1123_DAY] != t2[0]) || (t1[RFC1123_DAY+1] != t2[1]) ) + return -1; + + /* Skip to the month */ + t2 += 3; + + if ( (t1[RFC1123_MONTH] != t2[0]) || (t1[RFC1123_MONTH+1] != t2[1]) || + (t1[RFC1123_MONTH+2] != t2[2]) ) + return -1; + + /* Skip to year */ + t2 += 4; + + if ( (t1[RFC1123_YEAR] != t2[0]) ) { + /* Assume t2 is RFC 850 format */ + if ( (t1[RFC1123_YEAR+2] != t2[0]) || (t1[RFC1123_YEAR+3] != t2[1]) ) + return -1; + + /* skip to hour */ + t2 += 3; + } else { + /* Assume t2 is RFC 1123 format */ + if ( (t1[RFC1123_YEAR+1] != t2[1]) || (t1[RFC1123_YEAR+2] != t2[2]) || + (t1[RFC1123_YEAR+3] != t2[3]) ) + return -1; + + /* skip to hour */ + t2 += 5; + } + + /* check date */ + for (index=0; index<8; index++) { + if ( t1[RFC1123_HOUR+index] != t2[index] ) + return -1; + } + + /* Ignore timezone */ + + return 0; +} + + +/* --------------------------- util_uri_is_evil --------------------------- */ + + +NSAPI_PUBLIC int util_uri_is_evil(char *t) +{ + register int x; + + for(x = 0; t[x]; ++x) { + if(t[x] == '/') { + if(t[x+1] == '/') + return 1; + if(t[x+1] == '.') { + switch(t[x+2]) { + case '.': + if((!t[x+3]) || (t[x+3] == '/')) + return 1; + case '/': + case '\0': + return 1; + } + } + } +#ifdef XP_WIN32 + /* On NT, the directory "abc...." is the same as "abc" + * The only cheap way to catch this globally is to disallow + * names with the trailing "."s. Hopefully this is not over + * restrictive + */ + if ((t[x] == '.') && ( (t[x+1] == '/') || (t[x+1] == '\0') )) { + return 1; + } +#endif + } + return 0; +} + +/* ---------------------------- util_uri_parse ---------------------------- */ + +NSAPI_PUBLIC void util_uri_parse(char *uri) +{ + int spos = 0, tpos = 0; + int l = strlen(uri); + + while(uri[spos]) { + if(uri[spos] == '/') { + if((spos != l) && (uri[spos+1] == '.')) { + if(uri[spos+2] == '/') + spos += 2; + else + if((spos <= (l-3)) && + (uri[spos+2] == '.') && (uri[spos+3] == '/')) { + spos += 3; + while((tpos > 0) && (uri[--tpos] != '/')) + uri[tpos] = '\0'; + } else + uri[tpos++] = uri[spos++]; + } else { + if(uri[spos+1] != '/') + uri[tpos++] = uri[spos++]; + else + spos++; + } + } else + uri[tpos++] = uri[spos++]; + } + uri[tpos] = '\0'; +} + + +/* -------------------- util_uri_unescape_and_normalize -------------------- */ + +#ifdef XP_WIN32 +/* The server calls this function to unescape the URI and also normalize + * the uri. Normalizing the uri converts all "\" characters in the URI + * and pathinfo portion to "/". Does not touch "\" in query strings. + */ +void util_uri_unescape_and_normalize(char *s) +{ + char *t, *u; + + for(t = s, u = s; *t; ++t, ++u) { + if((*t == '%') && t[1] && t[2]) { + *u = ((t[1] >= 'A' ? ((t[1] & 0xdf) - 'A')+10 : (t[1] - '0'))*16) + + (t[2] >= 'A' ? ((t[2] & 0xdf) - 'A')+10 : (t[2] - '0')); + t += 2; + } + else + if(u != t) + *u = *t; + if (*u == '\\') /* normalize */ + *u = '/'; + } + *u = *t; +} +#endif /* XP_WIN32 */ + +/* -------------------------- util_uri_unescape --------------------------- */ + +NSAPI_PUBLIC void util_uri_unescape(char *s) +{ + char *t, *u; + + for(t = s, u = s; *t; ++t, ++u) { + if((*t == '%') && t[1] && t[2]) { + *u = ((t[1] >= 'A' ? ((t[1] & 0xdf) - 'A')+10 : (t[1] - '0'))*16) + + (t[2] >= 'A' ? ((t[2] & 0xdf) - 'A')+10 : (t[2] - '0')); + t += 2; + } + else + if(u != t) + *u = *t; + } + *u = *t; +} + + +/* --------------------------- util_uri_escape ---------------------------- */ + + +NSAPI_PUBLIC char *util_uri_escape(char *od, char *s) +{ + char *d; + + if(!od) + od = (char *) MALLOC((strlen(s)*3) + 1); + d = od; + + while(*s) { + if(strchr("% ?#:+&*\"<>\r\n", *s)) { + sprintf(d, "%%%2x", *s); + ++s; d += 3; + } + else + *d++ = *s++; + } + *d = '\0'; + return od; +} + + +/* --------------------------- util_url_escape ---------------------------- */ + + +NSAPI_PUBLIC char *util_url_escape(char *od, char *s) +{ + char *d; + + if(!od) + od = (char *) MALLOC((strlen(s)*3) + 1); + d = od; + + while(*s) { + if(strchr("% +*\"<>\r\n", *s)) { + sprintf(d, "%%%.2x", *s); + ++s; d += 3; + } + else + *d++ = *s++; + } + *d = '\0'; + return od; +} + + +/* ------------------------- util_mime_separator -------------------------- */ + + +NSAPI_PUBLIC int util_mime_separator(char *sep) +{ + srand(time(NULL)); + return util_sprintf(sep, "%c%c--%d%d%d", CR, LF, rand(), rand(), rand()); +} + + +/* ------------------------------ util_itoa ------------------------------- */ + + +/* + * Assumption: Reversing the digits will be faster in the general case + * than doing a log10 or some nasty trick to find the # of digits. + */ + +NSAPI_PUBLIC int util_itoa(int i, char *a) +{ + register int x, y, p; + register char c; + int negative; + + negative = 0; + if(i < 0) { + *a++ = '-'; + negative = 1; + i = -i; + } + p = 0; + while(i > 9) { + a[p++] = (i%10) + '0'; + i /= 10; + } + a[p++] = i + '0'; + + if(p > 1) { + for(x = 0, y = p - 1; x < y; ++x, --y) { + c = a[x]; + a[x] = a[y]; + a[y] = c; + } + } + a[p] = '\0'; + return p + negative; +} + + +/* ----------------------------- util_sprintf ----------------------------- */ + + +#include "prprf.h" + +/* + XXXrobm the NSPR interfaces don't allow me to just pass in a buffer + without a size + */ +#define UTIL_PRF_MAXSIZE 1048576 + +NSAPI_PUBLIC int util_vsnprintf(char *s, int n, register const char *fmt, + va_list args) +{ + return PR_vsnprintf(s, n, fmt, args); +} + +NSAPI_PUBLIC int util_snprintf(char *s, int n, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + return PR_vsnprintf(s, n, fmt, args); +} + +NSAPI_PUBLIC int util_vsprintf(char *s, register const char *fmt, va_list args) +{ + return PR_vsnprintf(s, UTIL_PRF_MAXSIZE, fmt, args); +} + +NSAPI_PUBLIC int util_sprintf(char *s, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + return PR_vsnprintf(s, UTIL_PRF_MAXSIZE, fmt, args); +} + +/* ---------------------------- util_sh_escape ---------------------------- */ + + +NSAPI_PUBLIC char *util_sh_escape(char *s) +{ + char *ns = (char *) MALLOC(strlen(s) * 2 + 1); /* worst case */ + register char *t, *u; + + for(t = s, u = ns; *t; ++t, ++u) { + if(strchr("&;`'\"|*?~<>^()[]{}$\\ #!", *t)) + *u++ = '\\'; + *u = *t; + } + *u = '\0'; + return ns; +} + +/* --------------------------- util_strcasecmp ---------------------------- */ + + +#ifdef NEED_STRCASECMP +/* These are stolen from mcom/lib/xp */ +NSAPI_PUBLIC +int util_strcasecmp(CASECMPARG_T char *one, CASECMPARG_T char *two) +{ + CASECMPARG_T char *pA; + CASECMPARG_T char *pB; + + for(pA=one, pB=two; *pA && *pB; pA++, pB++) + { + int tmp = tolower(*pA) - tolower(*pB); + if (tmp) + return tmp; + } + if (*pA) + return 1; + if (*pB) + return -1; + return 0; +} +#endif /* NEED_STRCASECMP */ + +#ifdef NEED_STRNCASECMP +NSAPI_PUBLIC +int util_strncasecmp(CASECMPARG_T char *one, CASECMPARG_T char *two, int n) +{ + CASECMPARG_T char *pA; + CASECMPARG_T char *pB; + + for(pA=one, pB=two;; pA++, pB++) + { + int tmp; + if (pA == one+n) + return 0; + if (!(*pA && *pB)) + return *pA - *pB; + tmp = tolower(*pA) - tolower(*pB); + if (tmp) + return tmp; + } +} +#endif /* NEED_STRNCASECMP */ + +#ifdef XP_WIN32 + + +/* util_delete_directory() + * This routine deletes all the files in a directory. If delete_directory is + * TRUE it will also delete the directory itself. + */ +VOID +util_delete_directory(char *FileName, BOOL delete_directory) +{ + HANDLE firstFile; + WIN32_FIND_DATA findData; + char *TmpFile, *NewFile; + + if (FileName == NULL) + return; + + TmpFile = (char *)MALLOC(strlen(FileName) + 5); + sprintf(TmpFile, "%s\\*.*", FileName); + firstFile = FindFirstFile(TmpFile, &findData); + FREE(TmpFile); + + if (firstFile == INVALID_HANDLE_VALUE) + return; + + if(strcmp(findData.cFileName, ".") && + strcmp(findData.cFileName, "..")) { + NewFile = (char *)MALLOC(strlen(FileName) + 1 + + strlen(findData.cFileName) + 1); + sprintf(NewFile, "%s\\%s",FileName, findData.cFileName); + DeleteFile(NewFile); + FREE(NewFile); + } + while (TRUE) { + if(!(FindNextFile(firstFile, &findData))) { + if (GetLastError() != ERROR_NO_MORE_FILES) { + ereport(LOG_WARN, XP_GetAdminStr(DBT_couldNotRemoveTemporaryDirectory_), FileName, GetLastError()); + } else { + FindClose(firstFile); + if (delete_directory) + if(!RemoveDirectory(FileName)) { + ereport(LOG_WARN, + XP_GetAdminStr(DBT_couldNotRemoveTemporaryDirectory_1), + FileName, GetLastError()); + } + return; + } + } else { + if(strcmp(findData.cFileName, ".") && + strcmp(findData.cFileName, "..")) { + NewFile = (char *)MALLOC(strlen(FileName) + 5 + + strlen(findData.cFileName) + 1); + sprintf(NewFile,"%s\\%s", FileName, findData.cFileName); + DeleteFile(NewFile); + FREE(NewFile); + } + } + } +} +#endif + +/* ------------------------------ util_strftime --------------------------- */ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strftime.c 5.11 (Berkeley) 2/24/91"; +#endif /* LIBC_SCCS and not lint */ + +#ifdef XP_UNIX +#include <sys/types.h> +#include <sys/time.h> +#include <string.h> +#include <stdio.h> +#endif + +static char *afmt[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", +}; +static char *Afmt[] = { + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", + "Saturday", +}; + +static char *bfmt[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", + "Oct", "Nov", "Dec", +}; +static char *Bfmt[] = { + "January", "February", "March", "April", "May", "June", "July", + "August", "September", "October", "November", "December", +}; + +#define TM_YEAR_BASE 1900 + +static void _util_strftime_conv(char *, int, int, char); + +#define _util_strftime_add(str) for (;(*pt = *str++); pt++); +#define _util_strftime_copy(str, len) memcpy(pt, str, len); pt += len; +#define _util_strftime_fmt util_strftime + +/* util_strftime() + * This is an optimized version of strftime for speed. Avoids the thread + * unsafeness of BSD strftime calls. + */ +int +util_strftime(char *pt, const char *format, const struct tm *t) +{ + char *start = pt; + char *scrap; + + for (; *format; ++format) { + if (*format == '%') + switch(*++format) { + case 'a': /* abbreviated weekday name */ + *pt++ = afmt[t->tm_wday][0]; + *pt++ = afmt[t->tm_wday][1]; + *pt++ = afmt[t->tm_wday][2]; + continue; + case 'd': /* day of month */ + _util_strftime_conv(pt, t->tm_mday, 2, '0'); + pt += 2; + continue; + case 'S': + _util_strftime_conv(pt, t->tm_sec, 2, '0'); + pt += 2; + continue; + case 'M': + _util_strftime_conv(pt, t->tm_min, 2, '0'); + pt += 2; + continue; + case 'H': + _util_strftime_conv(pt, t->tm_hour, 2, '0'); + pt += 2; + continue; + case 'Y': + if (t->tm_year < 100) { + *pt++ = '1'; + *pt++ = '9'; + _util_strftime_conv(pt, t->tm_year, 2, '0'); + } else { + /* will fail after 2100; but who cares? */ + *pt++ = '2'; + *pt++ = '0'; + _util_strftime_conv(pt, t->tm_year-100, 2, '0'); + } + pt += 2; + continue; + case 'b': /* abbreviated month name */ + case 'h': + *pt++ = bfmt[t->tm_mon][0]; + *pt++ = bfmt[t->tm_mon][1]; + *pt++ = bfmt[t->tm_mon][2]; + continue; + case 'T': + case 'X': + pt += _util_strftime_fmt(pt, "%H:%M:%S", t); + continue; + case '\0': + --format; + break; + case 'A': + if (t->tm_wday < 0 || t->tm_wday > 6) + return(0); + scrap = Afmt[t->tm_wday]; + _util_strftime_add(scrap); + continue; + case 'B': + if (t->tm_mon < 0 || t->tm_mon > 11) + return(0); + scrap = Bfmt[t->tm_mon]; + _util_strftime_add(scrap); + continue; + case 'C': + pt += _util_strftime_fmt(pt, "%a %b %e %H:%M:%S %Y", t); + continue; + case 'c': + pt += _util_strftime_fmt(pt, "%m/%d/%y %H:%M:%S", t); + continue; + case 'D': + pt += _util_strftime_fmt(pt, "%m/%d/%y", t); + continue; + case 'e': + _util_strftime_conv(pt, t->tm_mday, 2, ' '); + pt += 2; + continue; + case 'I': + _util_strftime_conv(pt, t->tm_hour % 12 ? + t->tm_hour % 12 : 12, 2, '0'); + pt += 2; + continue; + case 'j': + _util_strftime_conv(pt, t->tm_yday + 1, 3, '0'); + pt += 3; + continue; + case 'k': + _util_strftime_conv(pt, t->tm_hour, 2, ' '); + pt += 2; + continue; + case 'l': + _util_strftime_conv(pt, t->tm_hour % 12 ? + t->tm_hour % 12 : 12, 2, ' '); + pt += 2; + continue; + case 'm': + _util_strftime_conv(pt, t->tm_mon + 1, 2, '0'); + pt += 2; + continue; + case 'n': + *pt = '\n'; + pt++; + continue; + case 'p': + if (t->tm_hour >= 12) { + *pt = 'P'; + pt++; + } else { + *pt = 'A'; + pt++; + } + *pt = 'M'; + pt++; + continue; + case 'R': + pt += _util_strftime_fmt(pt, "%H:%M", t); + continue; + case 'r': + pt += _util_strftime_fmt(pt, "%I:%M:%S %p", t); + continue; + case 't': + *pt = '\t'; + pt++; + continue; + case 'U': + _util_strftime_conv(pt, (t->tm_yday + 7 - t->tm_wday) / 7, + 2, '0'); + pt += 2; + continue; + case 'W': + _util_strftime_conv(pt, (t->tm_yday + 7 - + (t->tm_wday ? (t->tm_wday - 1) : 6)) + / 7, 2, '0'); + pt += 2; + continue; + case 'w': + _util_strftime_conv(pt, t->tm_wday, 1, '0'); + pt += 1; + continue; + case 'x': + pt += _util_strftime_fmt(pt, "%m/%d/%y", t); + continue; + case 'y': + _util_strftime_conv(pt, (t->tm_year + TM_YEAR_BASE) + % 100, 2, '0'); + pt += 2; + continue; + case '%': + /* + * X311J/88-090 (4.12.3.5): if conversion char is + * undefined, behavior is undefined. Print out the + * character itself as printf(3) does. + */ + default: + break; + } + *pt = *format; + pt++; + } + + start[pt-start] = '\0'; + + return pt - start; +} + +static void +_util_strftime_conv(char *pt, int n, int digits, char pad) +{ + static char buf[10]; + register char *p; + + if (n >= 100) { + p = buf + sizeof(buf)-2; + for (; n > 0 && p > buf; n /= 10, --digits) + *p-- = n % 10 + '0'; + while (p > buf && digits-- > 0) + *p-- = pad; + p++; + _util_strftime_add(p); + } else { + int tens; + int ones = n; + + tens = 0; + if ( ones >= 10 ) { + while ( ones >= 10 ) { + tens++; + ones = ones - 10; + } + *pt++ = '0'+tens; + digits--; + } + else + *pt++ = '0'; + *pt++ = '0'+ones; + digits--; + while(digits--) + *pt++ = pad; + } + return; +} + + +#ifdef XP_UNIX +/* + * Local Thread Safe version of waitpid. This prevents the process + * from blocking in the system call. + */ +NSAPI_PUBLIC pid_t +util_waitpid(pid_t pid, int *statptr, int options) +{ + pid_t rv; + + for(rv = 0; !rv; PR_Sleep(500)) { + rv = waitpid(pid, statptr, options | WNOHANG); + if (rv == -1) { + if (errno == EINTR) + rv = 0; /* sleep and try again */ + else + ereport(LOG_WARN, "waitpid failed for pid %d:%s", pid, system_errmsg()); + } + } + return rv; +} +#endif + +/* + * Various reentrant routines by mikep. See util.h and systems.h + */ + +/* + * These are only necessary if we turn on interrupts in NSPR + */ +#ifdef NEED_RELOCKS +#include "crit.h" +#define RE_LOCK(name) \ + static CRITICAL name##_crit = 0; \ + if (name##_crit == 0) name##_crit = crit_init(); \ + crit_enter(name##_crit) + +#define RE_UNLOCK(name) crit_exit(name##_crit) + +#else +#define RE_LOCK(name) /* nada */ +#define RE_UNLOCK(name) /* nil */ +#endif + + +NSAPI_PUBLIC char * +util_strtok(register char *s, + register const char *delim, + register char **lasts) +{ +#ifdef HAVE_STRTOK_R + return strtok_r(s, delim, lasts); +#else + /* + * THIS IS THE THREAD SAFE VERSION OF strtok captured from + * public NetBSD. Note that no locks are needed + */ + register char *spanp; + register int c, sc; + char *tok; + + if (s == NULL && (s = *lasts) == NULL) + return (NULL); + + /* + * Skip (span) leading delimiters (s += strspn(s, delim), + * sort of). + */ + +cont: + c = *s++; + for (spanp = (char *)delim; (sc = *spanp++) != 0;) { + if (c == sc) + goto cont; + } + + if (c == 0) { /* no non-delimiter characters */ + *lasts = NULL; + return (NULL); + } + tok = s - 1; + + /* + * Scan token (scan for delimiters: s += strcspn(s, delim), + * sort of). + * Note that delim must have one NUL; we stop if we see that, too. + */ + for (;;) { + c = *s++; + spanp = (char *)delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *lasts = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +#endif /* no strtok_r */ +} + +#ifndef XP_WIN32 +NSAPI_PUBLIC struct passwd * +util_getpwnam(const char *name, struct passwd *result, char *buffer, + int buflen) +{ +#ifdef HAVE_PW_R + +#ifdef AIX +#if OSVERSION >= 4320 + return ((int)getpwnam_r(name, result, buffer, buflen, 0) == 0 ? result : NULL); +#else + return ((int)getpwnam_r(name, result, buffer, buflen) == 0 ? result : NULL); +#endif +#else + return getpwnam_r(name, result, buffer, buflen); +#endif /* AIX */ + +#else + char *lastp; + struct passwd *r; + RE_LOCK(pw); + r = getpwnam(name); + if (!r) + return r; + + result->pw_gid = r->pw_gid; + result->pw_uid = r->pw_uid; + /* Hope this buffer is long enough */ + if (buffer) + util_snprintf(buffer, buflen, "%s:%s:%d:%d:%s:%s:%s", r->pw_name, r->pw_passwd, + r->pw_uid, r->pw_gid, r->pw_gecos, r->pw_dir, r->pw_shell); + RE_UNLOCK(pw); + + result->pw_name = util_strtok(buffer, ":", &lastp); + result->pw_passwd = util_strtok(NULL, ":", &lastp); + (void) util_strtok(NULL, ":", &lastp); + (void) util_strtok(NULL, ":", &lastp); + result->pw_gecos = util_strtok(NULL, ":", &lastp); + result->pw_dir = util_strtok(NULL, ":", &lastp); + result->pw_shell = util_strtok(NULL, ":", &lastp); + return result; +#endif +} +#endif + +NSAPI_PUBLIC struct tm * +util_localtime(const time_t *clock, struct tm *res) +{ +#ifdef HAVE_TIME_R + return localtime_r(clock, res); +#else + struct tm *rv; + time_t zero = 0x7fffffff; + + RE_LOCK(localtime); + RE_UNLOCK(localtime); + rv = localtime(clock); + if (!rv) + rv = localtime(&zero); + if (rv) + *res = *rv; + else + return NULL; + return res; +#endif +} + + +NSAPI_PUBLIC char * +util_ctime(const time_t *clock, char *buf, int buflen) +{ +/* + * From cgi-src/restore.c refering to XP_WIN32: + * MLM - gross, but it works, better now FLC + */ +#if !defined(HAVE_TIME_R) || defined(XP_WIN32) + RE_LOCK(ctime); + strncpy(buf, ctime(clock), buflen); + buf[buflen - 1] = '\0'; + RE_UNLOCK(ctime); + return buf; +#elif HAVE_TIME_R == 2 + return ctime_r(clock, buf); +#else /* HAVE_TIME_R == 3 */ + return ctime_r(clock, buf, buflen); +#endif +} + +NSAPI_PUBLIC struct tm * +util_gmtime(const time_t *clock, struct tm *res) +{ +#ifdef HAVE_TIME_R + return gmtime_r(clock, res); +#else + struct tm *rv; + time_t zero = 0x7fffffff; + + RE_LOCK(gmtime); + rv = gmtime(clock); + RE_UNLOCK(gmtime); + if (!rv) + rv = gmtime(&zero); + if (rv) + *res = *rv; + else + return NULL; + + return res; +#endif +} + +NSAPI_PUBLIC char * +util_asctime(const struct tm *tm, char *buf, int buflen) +{ +#if HAVE_TIME_R == 2 + return asctime_r(tm, buf); +#elif HAVE_TIME_R == 3 + return asctime_r(tm, buf, buflen); +#else + RE_LOCK(asctime); + strncpy(buf, asctime(tm), buflen); + buf[buflen - 1] = '\0'; + RE_UNLOCK(asctime); + return buf; +#endif +} + +NSAPI_PUBLIC char * +util_strerror(int errnum, char *msg, int buflen) +{ +#ifdef HAVE_STRERROR_R + /* More IBM real-genius */ + return ((int)strerror_r(errnum, msg, buflen) > 0) ? msg : NULL; +#else + /* RE_LOCK(strerror); I don't think this is worth the trouble */ + (void)strncpy(msg, strerror(errnum), buflen); + msg[buflen - 1] = '\0'; + return msg; + /* RE_UNLOCK(strerror); */ +#endif +} + + + +/* ------------------------------- OLD CODE ------------------------------- */ + + +#if 0 + +NSAPI_PUBLIC int util_vsnprintf(char *s, int n, register char *fmt, + va_list args) +{ + register int pos = 0, max = (n > 2 ? n-2 : -1), boundson; + register char c, *t; + + if((max == -1) && (n != -1)) + goto punt; + + boundson = (n != -1); + while(*fmt) { + if(boundson && (pos > max)) + break; + c = *fmt++; + switch(c) { + case '%': + switch(*fmt++) { + case 'd': + if(boundson && ((pos + 10) > max)) + goto punt; + pos += util_itoa(va_arg(args, int), &s[pos]); + break; + case 's': + t = va_arg(args, char *); + while(*t) { + s[pos++] = *t++; + if(boundson && (pos > max)) + goto punt; + } + break; + case 'c': + s[pos++] = (char) va_arg(args, int); + break; + case '%': + s[pos++] = '%'; + break; + } + break; + case '\\': + if( (s[pos++] = *fmt) ) + ++fmt; + break; + default: + s[pos++] = c; + } + } + punt: + s[pos] = '\0'; + + va_end(args); + return pos; +} + +NSAPI_PUBLIC int util_snprintf(char *s, int n, char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + return util_vsnprintf(s, n, fmt, args); +} + +NSAPI_PUBLIC int util_vsprintf(char *s, register char *fmt, va_list args) +{ + return util_vsnprintf(s, -1, fmt, args); +} + +NSAPI_PUBLIC int util_sprintf(char *s, char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + return util_vsnprintf(s, -1, fmt, args); +} +#endif |