add js to tree

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3693 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Brian West committed 2006-12-18 15:53:47 +00:00
1 parent 855c7b9a77
commit fff98f6316
1137 files changed
+386873

No files matched your search

+1
View File
@@ -0,0 +1 @@
Makefile
+19
View File
@@ -0,0 +1,19 @@
/.cvsignore/1.2/Sat May 12 04:14:49 2001//
/Makefile.in/1.13/Sun Apr 25 15:00:58 2004//
/prdir.c/3.7/Sun Apr 25 15:00:58 2004//
/prfdcach.c/3.12/Sun Apr 25 15:00:58 2004//
/prfile.c/3.44/Tue Feb 7 01:21:00 2006//
/prio.c/3.19/Fri Oct 21 18:21:42 2005//
/priometh.c/3.19/Sun Apr 25 15:00:58 2004//
/pripv6.c/3.12/Tue Jan 25 19:44:07 2005//
/prlayer.c/3.19/Sun Apr 25 15:00:58 2004//
/prlog.c/3.34/Mon Mar 14 21:40:15 2005//
/prmapopt.c/3.18/Sun Apr 25 15:00:58 2004//
/prmmap.c/3.7/Sun Apr 25 15:00:58 2004//
/prmwait.c/3.18/Tue Mar 8 22:40:15 2005//
/prpolevt.c/3.15/Sun Apr 25 15:00:58 2004//
/prprf.c/3.18/Fri Jul 1 21:01:40 2005//
/prscanf.c/3.11/Fri Aug 5 22:44:06 2005//
/prsocket.c/3.58/Fri Oct 21 18:21:42 2005//
/prstdio.c/3.6/Sun Apr 25 15:00:58 2004//
D
+1
View File
@@ -0,0 +1 @@
mozilla/nsprpub/pr/src/io
+1
View File
@@ -0,0 +1 @@
:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot
+97
View File
@@ -0,0 +1,97 @@
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is the Netscape Portable Runtime (NSPR).
#
# The Initial Developer of the Original Code is
# Netscape Communications Corporation.
# Portions created by the Initial Developer are Copyright (C) 1998-2000
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
#! gmake
MOD_DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(MOD_DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/config.mk
# Disable optimization of the nspr on SunOS4.1.3
ifeq ($(OS_ARCH),SunOS)
ifeq ($(OS_RELEASE),4.1.3_U1)
OPTIMIZER =
endif
endif
CSRCS = \
prfdcach.c \
prmwait.c \
priometh.c \
pripv6.c \
prmapopt.c \
prlayer.c \
prlog.c \
prmmap.c \
prpolevt.c \
prprf.c \
prscanf.c \
prstdio.c \
$(NULL)
ifndef USE_PTHREADS
CSRCS += \
prdir.c \
prfile.c \
prio.c \
prsocket.c \
$(NULL)
endif
TARGETS = $(OBJS)
INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private
DEFINES += -D_NSPR_BUILD_
include $(topsrcdir)/config/rules.mk
# An OS/2 Optimization bug causes PR_snprintf() to produce wrong result.
# This suppresses optimization for this single compilation unit.
ifeq ($(MOZ_OS2_TOOLS),VACPP)
$(OBJDIR)/prprf.obj: prprf.c
@$(MAKE_OBJDIR)
$(CC) -Fo$@ -c $(filter-out /O+, $(CFLAGS)) $<
endif
export:: $(TARGETS)
+164
View File
@@ -0,0 +1,164 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape Portable Runtime (NSPR).
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Roy Yokoyama <yokoyama@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "primpl.h"
PR_IMPLEMENT(PRDir*) PR_OpenDir(const char *name)
{
PRDir *dir;
PRStatus sts;
dir = PR_NEW(PRDir);
if (dir) {
sts = _PR_MD_OPEN_DIR(&dir->md,name);
if (sts != PR_SUCCESS) {
PR_DELETE(dir);
return NULL;
}
} else {
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
}
return dir;
}
PR_IMPLEMENT(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags)
{
/* _MD_READ_DIR return a char* to the name; allocation in machine-dependent code */
char* name = _PR_MD_READ_DIR(&dir->md, flags);
dir->d.name = name;
return name ? &dir->d : NULL;
}
PR_IMPLEMENT(PRStatus) PR_CloseDir(PRDir *dir)
{
PRInt32 rv;
if (dir) {
rv = _PR_MD_CLOSE_DIR(&dir->md);
PR_DELETE(dir);
if (rv < 0) {
return PR_FAILURE;
} else
return PR_SUCCESS;
}
return PR_SUCCESS;
}
PR_IMPLEMENT(PRStatus) PR_MkDir(const char *name, PRIntn mode)
{
PRInt32 rv;
rv = _PR_MD_MKDIR(name, mode);
if (rv < 0) {
return PR_FAILURE;
} else
return PR_SUCCESS;
}
PR_IMPLEMENT(PRStatus) PR_MakeDir(const char *name, PRIntn mode)
{
PRInt32 rv;
if (!_pr_initialized) _PR_ImplicitInitialization();
rv = _PR_MD_MAKE_DIR(name, mode);
if (rv < 0) {
return PR_FAILURE;
} else
return PR_SUCCESS;
}
PR_IMPLEMENT(PRStatus) PR_RmDir(const char *name)
{
PRInt32 rv;
rv = _PR_MD_RMDIR(name);
if (rv < 0) {
return PR_FAILURE;
} else
return PR_SUCCESS;
}
#ifdef MOZ_UNICODE
/*
* UTF16 Interface
*/
PR_IMPLEMENT(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar *name)
{
PRDirUTF16 *dir;
PRStatus sts;
dir = PR_NEW(PRDirUTF16);
if (dir) {
sts = _PR_MD_OPEN_DIR_UTF16(&dir->md,name);
if (sts != PR_SUCCESS) {
PR_DELETE(dir);
return NULL;
}
} else {
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
}
return dir;
}
PR_IMPLEMENT(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags)
{
/*
* _MD_READ_DIR_UTF16 return a PRUnichar* to the name; allocation in
* machine-dependent code
*/
PRUnichar* name = _PR_MD_READ_DIR_UTF16(&dir->md, flags);
dir->d.name = name;
return name ? &dir->d : NULL;
}
PR_IMPLEMENT(PRStatus) PR_CloseDirUTF16(PRDirUTF16 *dir)
{
PRInt32 rv;
if (dir) {
rv = _PR_MD_CLOSE_DIR_UTF16(&dir->md);
PR_DELETE(dir);
if (rv < 0)
return PR_FAILURE;
else
return PR_SUCCESS;
}
return PR_SUCCESS;
}
#endif /* MOZ_UNICODE */
+311
View File
@@ -0,0 +1,311 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape Portable Runtime (NSPR).
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "primpl.h"
#include <string.h>
/*****************************************************************************/
/*****************************************************************************/
/************************** File descriptor caching **************************/
/*****************************************************************************/
/*****************************************************************************/
/*
** This code is built into debuggable versions of NSPR to assist in
** finding misused file descriptors. Since file descritors (PRFileDesc)
** are identified by a pointer to their structure, they can be the
** target of dangling references. Furthermore, NSPR caches and tries
** to aggressively reuse file descriptors, leading to more ambiguity.
** The following code will allow a debugging client to set environment
** variables and control the number of file descriptors that will be
** preserved before they are recycled. The environment variables are
** NSPR_FD_CACHE_SIZE_LOW and NSPR_FD_CACHE_SIZE_HIGH. The former sets
** the number of descriptors NSPR will allocate before beginning to
** recycle. The latter is the maximum number permitted in the cache
** (exclusive of those in use) at a time.
*/
typedef struct _PR_Fd_Cache
{
PRLock *ml;
PRIntn count;
PRStack *stack;
PRFileDesc *head, *tail;
PRIntn limit_low, limit_high;
} _PR_Fd_Cache;
static _PR_Fd_Cache _pr_fd_cache;
static PRFileDesc **stack2fd = &(((PRFileDesc*)NULL)->higher);
/*
** Get a FileDescriptor from the cache if one exists. If not allocate
** a new one from the heap.
*/
PRFileDesc *_PR_Getfd(void)
{
PRFileDesc *fd;
/*
** $$$
** This may look a little wasteful. We'll see. Right now I want to
** be able to toggle between caching and not at runtime to measure
** the differences. If it isn't too annoying, I'll leave it in.
** $$$$
**
** The test is against _pr_fd_cache.limit_high. If that's zero,
** we're not doing the extended cache but going for performance.
*/
if (0 == _pr_fd_cache.limit_high)
{
PRStackElem *pop;
PR_ASSERT(NULL != _pr_fd_cache.stack);
pop = PR_StackPop(_pr_fd_cache.stack);
if (NULL == pop) goto allocate;
fd = (PRFileDesc*)((PRPtrdiff)pop - (PRPtrdiff)stack2fd);
}
else
{
do
{
if (NULL == _pr_fd_cache.head) goto allocate; /* nothing there */
if (_pr_fd_cache.count < _pr_fd_cache.limit_low) goto allocate;
/* we "should" be able to extract an fd from the cache */
PR_Lock(_pr_fd_cache.ml); /* need the lock to do this safely */
fd = _pr_fd_cache.head; /* protected extraction */
if (NULL == fd) /* unexpected, but not fatal */
{
PR_ASSERT(0 == _pr_fd_cache.count);
PR_ASSERT(NULL == _pr_fd_cache.tail);
}
else
{
_pr_fd_cache.count -= 1;
_pr_fd_cache.head = fd->higher;
if (NULL == _pr_fd_cache.head)
{
PR_ASSERT(0 == _pr_fd_cache.count);
_pr_fd_cache.tail = NULL;
}
PR_ASSERT(&_pr_faulty_methods == fd->methods);
PR_ASSERT(PR_INVALID_IO_LAYER == fd->identity);
PR_ASSERT(_PR_FILEDESC_FREED == fd->secret->state);
}
PR_Unlock(_pr_fd_cache.ml);
} while (NULL == fd); /* then go around and allocate a new one */
}
finished:
fd->dtor = NULL;
fd->lower = fd->higher = NULL;
fd->identity = PR_NSPR_IO_LAYER;
memset(fd->secret, 0, sizeof(PRFilePrivate));
return fd;
allocate:
fd = PR_NEW(PRFileDesc);
if (NULL != fd)
{
fd->secret = PR_NEW(PRFilePrivate);
if (NULL == fd->secret) PR_DELETE(fd);
}
if (NULL != fd) goto finished;
else return NULL;
} /* _PR_Getfd */
/*
** Return a file descriptor to the cache unless there are too many in
** there already. If put in cache, clear the fields first.
*/
void _PR_Putfd(PRFileDesc *fd)
{
PR_ASSERT(PR_NSPR_IO_LAYER == fd->identity);
fd->methods = &_pr_faulty_methods;
fd->identity = PR_INVALID_IO_LAYER;
fd->secret->state = _PR_FILEDESC_FREED;
if (0 == _pr_fd_cache.limit_high)
{
PR_StackPush(_pr_fd_cache.stack, (PRStackElem*)(&fd->higher));
}
else
{
if (_pr_fd_cache.count > _pr_fd_cache.limit_high)
{
PR_Free(fd->secret);
PR_Free(fd);
}
else
{
PR_Lock(_pr_fd_cache.ml);
if (NULL == _pr_fd_cache.tail)
{
PR_ASSERT(0 == _pr_fd_cache.count);
PR_ASSERT(NULL == _pr_fd_cache.head);
_pr_fd_cache.head = _pr_fd_cache.tail = fd;
}
else
{
PR_ASSERT(NULL == _pr_fd_cache.tail->higher);
_pr_fd_cache.tail->higher = fd;
_pr_fd_cache.tail = fd; /* new value */
}
fd->higher = NULL; /* always so */
_pr_fd_cache.count += 1; /* count the new entry */
PR_Unlock(_pr_fd_cache.ml);
}
}
} /* _PR_Putfd */
PR_IMPLEMENT(PRStatus) PR_SetFDCacheSize(PRIntn low, PRIntn high)
{
/*
** This can be called at any time, may adjust the cache sizes,
** turn the caches off, or turn them on. It is not dependent
** on the compilation setting of DEBUG.
*/
if (!_pr_initialized) _PR_ImplicitInitialization();
if (low > high) low = high; /* sanity check the params */
PR_Lock(_pr_fd_cache.ml);
if (0 == high) /* shutting down or staying down */
{
if (0 != _pr_fd_cache.limit_high) /* shutting down */
{
_pr_fd_cache.limit_high = 0; /* stop use */
/*
** Hold the lock throughout - nobody's going to want it
** other than another caller to this routine. Just don't
** let that happen.
**
** Put all the cached fds onto the new cache.
*/
while (NULL != _pr_fd_cache.head)
{
PRFileDesc *fd = _pr_fd_cache.head;
_pr_fd_cache.head = fd->higher;
PR_StackPush(_pr_fd_cache.stack, (PRStackElem*)(&fd->higher));
}
_pr_fd_cache.limit_low = 0;
_pr_fd_cache.tail = NULL;
_pr_fd_cache.count = 0;
}
}
else /* starting up or just adjusting parameters */
{
PRBool was_using_stack = (0 == _pr_fd_cache.limit_high);
_pr_fd_cache.limit_low = low;
_pr_fd_cache.limit_high = high;
if (was_using_stack) /* was using stack - feed into cache */
{
PRStackElem *pop;
while (NULL != (pop = PR_StackPop(_pr_fd_cache.stack)))
{
PRFileDesc *fd = (PRFileDesc*)
((PRPtrdiff)pop - (PRPtrdiff)stack2fd);
if (NULL == _pr_fd_cache.tail) _pr_fd_cache.tail = fd;
fd->higher = _pr_fd_cache.head;
_pr_fd_cache.head = fd;
_pr_fd_cache.count += 1;
}
}
}
PR_Unlock(_pr_fd_cache.ml);
return PR_SUCCESS;
} /* PR_SetFDCacheSize */
void _PR_InitFdCache(void)
{
/*
** The fd caching is enabled by default for DEBUG builds,
** disabled by default for OPT builds. That default can
** be overridden at runtime using environment variables
** or a super-wiz-bang API.
*/
const char *low = PR_GetEnv("NSPR_FD_CACHE_SIZE_LOW");
const char *high = PR_GetEnv("NSPR_FD_CACHE_SIZE_HIGH");
/*
** _low is allowed to be zero, _high is not.
** If _high is zero, we're not doing the caching.
*/
_pr_fd_cache.limit_low = 0;
#if defined(DEBUG)
_pr_fd_cache.limit_high = FD_SETSIZE;
#else
_pr_fd_cache.limit_high = 0;
#endif /* defined(DEBUG) */
if (NULL != low) _pr_fd_cache.limit_low = atoi(low);
if (NULL != high) _pr_fd_cache.limit_high = atoi(high);
if (_pr_fd_cache.limit_high < _pr_fd_cache.limit_low)
_pr_fd_cache.limit_high = _pr_fd_cache.limit_low;
_pr_fd_cache.ml = PR_NewLock();
PR_ASSERT(NULL != _pr_fd_cache.ml);
_pr_fd_cache.stack = PR_CreateStack("FD");
PR_ASSERT(NULL != _pr_fd_cache.stack);
} /* _PR_InitFdCache */
void _PR_CleanupFdCache(void)
{
PRFileDesc *fd, *next;
PRStackElem *pop;
for (fd = _pr_fd_cache.head; fd != NULL; fd = next)
{
next = fd->higher;
PR_DELETE(fd->secret);
PR_DELETE(fd);
}
PR_DestroyLock(_pr_fd_cache.ml);
while ((pop = PR_StackPop(_pr_fd_cache.stack)) != NULL)
{
fd = (PRFileDesc*)((PRPtrdiff)pop - (PRPtrdiff)stack2fd);
PR_DELETE(fd->secret);
PR_DELETE(fd);
}
PR_DestroyStack(_pr_fd_cache.stack);
} /* _PR_CleanupFdCache */
/* prfdcach.c */
+846
View File
@@ -0,0 +1,846 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape Portable Runtime (NSPR).
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "primpl.h"
#include <string.h>
#include <fcntl.h>
#ifdef XP_UNIX
#if defined(AIX) || defined(QNX)
/* To pick up sysconf */
#include <unistd.h>
#else
/* To pick up getrlimit, setrlimit */
#include <sys/time.h>
#include <sys/resource.h>
#endif
#endif /* XP_UNIX */
extern PRLock *_pr_flock_lock;
extern PRCondVar *_pr_flock_cv;
static PRInt32 PR_CALLBACK FileRead(PRFileDesc *fd, void *buf, PRInt32 amount)
{
PRInt32 rv = 0;
PRThread *me = _PR_MD_CURRENT_THREAD();
if (_PR_PENDING_INTERRUPT(me)) {
me->flags &= ~_PR_INTERRUPT;
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
rv = -1;
}
if (_PR_IO_PENDING(me)) {
PR_SetError(PR_IO_PENDING_ERROR, 0);
rv = -1;
}
if (rv == -1)
return rv;
rv = _PR_MD_READ(fd, buf, amount);
if (rv < 0) {
PR_ASSERT(rv == -1);
}
PR_LOG(_pr_io_lm, PR_LOG_MAX, ("read -> %d", rv));
return rv;
}
static PRInt32 PR_CALLBACK FileWrite(PRFileDesc *fd, const void *buf, PRInt32 amount)
{
PRInt32 rv = 0;
PRInt32 temp, count;
PRThread *me = _PR_MD_CURRENT_THREAD();
if (_PR_PENDING_INTERRUPT(me)) {
me->flags &= ~_PR_INTERRUPT;
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
rv = -1;
}
if (_PR_IO_PENDING(me)) {
PR_SetError(PR_IO_PENDING_ERROR, 0);
rv = -1;
}
if (rv != 0)
return rv;
count = 0;
#if !defined(_PR_HAVE_O_APPEND) /* Bugzilla: 4090, 276330 */
if ( PR_TRUE == fd->secret->appendMode ) {
rv = PR_Seek(fd, 0, PR_SEEK_END );
if ( -1 == rv ) {
return rv;
}
} /* if (fd->secret->appendMode...) */
#endif /* _PR_HAVE_O_APPEND */
while (amount > 0) {
temp = _PR_MD_WRITE(fd, buf, amount);
if (temp < 0) {
count = -1;
break;
}
count += temp;
if (fd->secret->nonblocking) {
break;
}
buf = (const void*) ((const char*)buf + temp);
amount -= temp;
}
PR_LOG(_pr_io_lm, PR_LOG_MAX, ("write -> %d", count));
return count;
}
static PROffset32 PR_CALLBACK FileSeek(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence)
{
PROffset32 result;
result = _PR_MD_LSEEK(fd, offset, whence);
return result;
}
static PROffset64 PR_CALLBACK FileSeek64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence)
{
#ifdef XP_MAC
#pragma unused( fd, offset, whence )
#endif
PROffset64 result;
result = _PR_MD_LSEEK64(fd, offset, whence);
return result;
}
static PRInt32 PR_CALLBACK FileAvailable(PRFileDesc *fd)
{
PRInt32 result, cur, end;
cur = _PR_MD_LSEEK(fd, 0, PR_SEEK_CUR);
if (cur >= 0)
end = _PR_MD_LSEEK(fd, 0, PR_SEEK_END);
if ((cur < 0) || (end < 0)) {
return -1;
}
result = end - cur;
_PR_MD_LSEEK(fd, cur, PR_SEEK_SET);
return result;
}
static PRInt64 PR_CALLBACK FileAvailable64(PRFileDesc *fd)
{
#ifdef XP_MAC
#pragma unused( fd )
#endif
PRInt64 result, cur, end;
PRInt64 minus_one;
LL_I2L(minus_one, -1);
cur = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_CUR);
if (LL_GE_ZERO(cur))
end = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_END);
if (!LL_GE_ZERO(cur) || !LL_GE_ZERO(end)) return minus_one;
LL_SUB(result, end, cur);
(void)_PR_MD_LSEEK64(fd, cur, PR_SEEK_SET);
return result;
}
static PRInt32 PR_CALLBACK PipeAvailable(PRFileDesc *fd)
{
PRInt32 rv;
rv = _PR_MD_PIPEAVAILABLE(fd);
return rv;
}
static PRInt64 PR_CALLBACK PipeAvailable64(PRFileDesc *fd)
{
PRInt64 rv;
LL_I2L(rv, _PR_MD_PIPEAVAILABLE(fd));
return rv;
}
static PRStatus PR_CALLBACK PipeSync(PRFileDesc *fd)
{
#if defined(XP_MAC)
#pragma unused (fd)
#endif
return PR_SUCCESS;
}
static PRStatus PR_CALLBACK FileGetInfo(PRFileDesc *fd, PRFileInfo *info)
{
PRInt32 rv;
rv = _PR_MD_GETOPENFILEINFO(fd, info);
if (rv < 0) {
return PR_FAILURE;
} else
return PR_SUCCESS;
}
static PRStatus PR_CALLBACK FileGetInfo64(PRFileDesc *fd, PRFileInfo64 *info)
{
#ifdef XP_MAC
#pragma unused( fd, info )
#endif
/* $$$$ NOT YET IMPLEMENTED */
PRInt32 rv;
rv = _PR_MD_GETOPENFILEINFO64(fd, info);
if (rv < 0) return PR_FAILURE;
else return PR_SUCCESS;
}
static PRStatus PR_CALLBACK FileSync(PRFileDesc *fd)
{
PRInt32 result;
result = _PR_MD_FSYNC(fd);
if (result < 0) {
return PR_FAILURE;
}
return PR_SUCCESS;
}
static PRStatus PR_CALLBACK FileClose(PRFileDesc *fd)
{
if (!fd || !fd->secret
|| (fd->secret->state != _PR_FILEDESC_OPEN
&& fd->secret->state != _PR_FILEDESC_CLOSED)) {
PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
return PR_FAILURE;
}
if (fd->secret->state == _PR_FILEDESC_OPEN) {
if (_PR_MD_CLOSE_FILE(fd->secret->md.osfd) < 0) {
return PR_FAILURE;
}
fd->secret->state = _PR_FILEDESC_CLOSED;
}
PR_FreeFileDesc(fd);
return PR_SUCCESS;
}
static PRInt16 PR_CALLBACK FilePoll(
PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
{
#ifdef XP_MAC
#pragma unused( fd, in_flags )
#endif
*out_flags = 0;
return in_flags;
} /* FilePoll */
static PRIOMethods _pr_fileMethods = {
PR_DESC_FILE,
FileClose,
FileRead,
FileWrite,
FileAvailable,
FileAvailable64,
FileSync,
FileSeek,
FileSeek64,
FileGetInfo,
FileGetInfo64,
(PRWritevFN)_PR_InvalidInt,
(PRConnectFN)_PR_InvalidStatus,
(PRAcceptFN)_PR_InvalidDesc,
(PRBindFN)_PR_InvalidStatus,
(PRListenFN)_PR_InvalidStatus,
(PRShutdownFN)_PR_InvalidStatus,
(PRRecvFN)_PR_InvalidInt,
(PRSendFN)_PR_InvalidInt,
(PRRecvfromFN)_PR_InvalidInt,
(PRSendtoFN)_PR_InvalidInt,
FilePoll,
(PRAcceptreadFN)_PR_InvalidInt,
(PRTransmitfileFN)_PR_InvalidInt,
(PRGetsocknameFN)_PR_InvalidStatus,
(PRGetpeernameFN)_PR_InvalidStatus,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt,
(PRGetsocketoptionFN)_PR_InvalidStatus,
(PRSetsocketoptionFN)_PR_InvalidStatus,
(PRSendfileFN)_PR_InvalidInt,
(PRConnectcontinueFN)_PR_InvalidStatus,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt
};
PR_IMPLEMENT(const PRIOMethods*) PR_GetFileMethods(void)
{
return &_pr_fileMethods;
}
static PRIOMethods _pr_pipeMethods = {
PR_DESC_PIPE,
FileClose,
FileRead,
FileWrite,
PipeAvailable,
PipeAvailable64,
PipeSync,
(PRSeekFN)_PR_InvalidInt,
(PRSeek64FN)_PR_InvalidInt64,
(PRFileInfoFN)_PR_InvalidStatus,
(PRFileInfo64FN)_PR_InvalidStatus,
(PRWritevFN)_PR_InvalidInt,
(PRConnectFN)_PR_InvalidStatus,
(PRAcceptFN)_PR_InvalidDesc,
(PRBindFN)_PR_InvalidStatus,
(PRListenFN)_PR_InvalidStatus,
(PRShutdownFN)_PR_InvalidStatus,
(PRRecvFN)_PR_InvalidInt,
(PRSendFN)_PR_InvalidInt,
(PRRecvfromFN)_PR_InvalidInt,
(PRSendtoFN)_PR_InvalidInt,
FilePoll,
(PRAcceptreadFN)_PR_InvalidInt,
(PRTransmitfileFN)_PR_InvalidInt,
(PRGetsocknameFN)_PR_InvalidStatus,
(PRGetpeernameFN)_PR_InvalidStatus,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt,
(PRGetsocketoptionFN)_PR_InvalidStatus,
(PRSetsocketoptionFN)_PR_InvalidStatus,
(PRSendfileFN)_PR_InvalidInt,
(PRConnectcontinueFN)_PR_InvalidStatus,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt
};
PR_IMPLEMENT(const PRIOMethods*) PR_GetPipeMethods(void)
{
return &_pr_pipeMethods;
}
PR_IMPLEMENT(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode)
{
PROsfd osfd;
PRFileDesc *fd = 0;
#if !defined(_PR_HAVE_O_APPEND)
PRBool appendMode = ( PR_APPEND & flags )? PR_TRUE : PR_FALSE;
#endif
if (!_pr_initialized) _PR_ImplicitInitialization();
/* Map pr open flags and mode to os specific flags */
osfd = _PR_MD_OPEN(name, flags, mode);
if (osfd != -1) {
fd = PR_AllocFileDesc(osfd, &_pr_fileMethods);
if (!fd) {
(void) _PR_MD_CLOSE_FILE(osfd);
} else {
#if !defined(_PR_HAVE_O_APPEND)
fd->secret->appendMode = appendMode;
#endif
_PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE);
}
}
return fd;
}
PR_IMPLEMENT(PRFileDesc*) PR_OpenFile(
const char *name, PRIntn flags, PRIntn mode)
{
PROsfd osfd;
PRFileDesc *fd = 0;
#if !defined(_PR_HAVE_O_APPEND)
PRBool appendMode = ( PR_APPEND & flags )? PR_TRUE : PR_FALSE;
#endif
if (!_pr_initialized) _PR_ImplicitInitialization();
/* Map pr open flags and mode to os specific flags */
osfd = _PR_MD_OPEN_FILE(name, flags, mode);
if (osfd != -1) {
fd = PR_AllocFileDesc(osfd, &_pr_fileMethods);
if (!fd) {
(void) _PR_MD_CLOSE_FILE(osfd);
} else {
#if !defined(_PR_HAVE_O_APPEND)
fd->secret->appendMode = appendMode;
#endif
_PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE);
}
}
return fd;
}
PR_IMPLEMENT(PRInt32) PR_GetSysfdTableMax(void)
{
#if defined(XP_UNIX) && !defined(AIX) && !defined(NEXTSTEP) && !defined(QNX)
struct rlimit rlim;
if ( getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
/* XXX need to call PR_SetError() */
return -1;
}
return rlim.rlim_max;
#elif defined(AIX) || defined(NEXTSTEP) || defined(QNX)
return sysconf(_SC_OPEN_MAX);
#elif defined(WIN32)
/*
* There is a systemwide limit of 65536 user handles.
*/
return 16384;
#elif defined (WIN16)
return FOPEN_MAX;
#elif defined(XP_OS2)
ULONG ulReqCount = 0;
ULONG ulCurMaxFH = 0;
DosSetRelMaxFH(&ulReqCount, &ulCurMaxFH);
return ulCurMaxFH;
#elif defined (XP_MAC) || defined(XP_BEOS)
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
return -1;
#else
write me;
#endif
}
PR_IMPLEMENT(PRInt32) PR_SetSysfdTableSize(int table_size)
{
#if defined(XP_UNIX) && !defined(AIX) && !defined(NEXTSTEP) && !defined(QNX)
struct rlimit rlim;
PRInt32 tableMax = PR_GetSysfdTableMax();
if (tableMax < 0)
return -1;
if (tableMax > FD_SETSIZE)
tableMax = FD_SETSIZE;
rlim.rlim_max = tableMax;
/* Grow as much as we can; even if too big */
if ( rlim.rlim_max < table_size )
rlim.rlim_cur = rlim.rlim_max;
else
rlim.rlim_cur = table_size;
if ( setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
/* XXX need to call PR_SetError() */
return -1;
}
return rlim.rlim_cur;
#elif defined(XP_OS2)
PRInt32 tableMax = PR_GetSysfdTableMax();
if (table_size > tableMax) {
APIRET rc = NO_ERROR;
rc = DosSetMaxFH(table_size);
if (rc == NO_ERROR)
return table_size;
else
return -1;
}
return tableMax;
#elif defined(AIX) || defined(NEXTSTEP) || defined(QNX) \
|| defined(WIN32) || defined(WIN16) || defined(XP_BEOS)
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
return -1;
#elif defined (XP_MAC)
#pragma unused (table_size)
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
return -1;
#else
write me;
#endif
}
PR_IMPLEMENT(PRStatus) PR_Delete(const char *name)
{
PRInt32 rv;
rv = _PR_MD_DELETE(name);
if (rv < 0) {
return PR_FAILURE;
} else
return PR_SUCCESS;
}
PR_IMPLEMENT(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info)
{
PRInt32 rv;
rv = _PR_MD_GETFILEINFO(fn, info);
if (rv < 0) {
return PR_FAILURE;
} else
return PR_SUCCESS;
}
PR_IMPLEMENT(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info)
{
#ifdef XP_MAC
#pragma unused (fn, info)
#endif
PRInt32 rv;
if (!_pr_initialized) _PR_ImplicitInitialization();
rv = _PR_MD_GETFILEINFO64(fn, info);
if (rv < 0) {
return PR_FAILURE;
} else {
return PR_SUCCESS;
}
}
PR_IMPLEMENT(PRStatus) PR_Rename(const char *from, const char *to)
{
PRInt32 rv;
rv = _PR_MD_RENAME(from, to);
if (rv < 0) {
return PR_FAILURE;
} else
return PR_SUCCESS;
}
PR_IMPLEMENT(PRStatus) PR_Access(const char *name, PRAccessHow how)
{
PRInt32 rv;
rv = _PR_MD_ACCESS(name, how);
if (rv < 0) {
return PR_FAILURE;
} else
return PR_SUCCESS;
}
/*
** Import an existing OS file to NSPR
*/
PR_IMPLEMENT(PRFileDesc*) PR_ImportFile(PROsfd osfd)
{
PRFileDesc *fd = NULL;
if (!_pr_initialized) _PR_ImplicitInitialization();
fd = PR_AllocFileDesc(osfd, &_pr_fileMethods);
if( !fd ) {
(void) _PR_MD_CLOSE_FILE(osfd);
} else {
_PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
}
return fd;
}
/*
** Import an existing OS pipe to NSPR
*/
PR_IMPLEMENT(PRFileDesc*) PR_ImportPipe(PROsfd osfd)
{
PRFileDesc *fd = NULL;
if (!_pr_initialized) _PR_ImplicitInitialization();
fd = PR_AllocFileDesc(osfd, &_pr_pipeMethods);
if( !fd ) {
(void) _PR_MD_CLOSE_FILE(osfd);
} else {
_PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
#ifdef WINNT
fd->secret->md.sync_file_io = PR_TRUE;
#endif
}
return fd;
}
#ifndef NO_NSPR_10_SUPPORT
/*
** PR_Stat() for Win16 is defined in w16io.c
** it is a hack to circumvent problems in Gromit and Java
** See also: BugSplat: 98516.
*/
#if !defined(WIN16)
/*
* This function is supposed to be for backward compatibility with
* nspr 1.0. Therefore, it still uses the nspr 1.0 error-reporting
* mechanism -- returns a PRInt32, which is the error code when the call
* fails.
*
* If we need this function in nspr 2.0, it should be changed to
* return PRStatus, as follows:
*
* PR_IMPLEMENT(PRStatus) PR_Stat(const char *name, struct stat *buf)
* {
* PRInt32 rv;
*
* rv = _PR_MD_STAT(name, buf);
* if (rv < 0)
* return PR_FAILURE;
* else
* return PR_SUCCESS;
* }
*
* -- wtc, 2/14/97.
*/
PR_IMPLEMENT(PRInt32) PR_Stat(const char *name, struct stat *buf)
{
PRInt32 rv;
rv = _PR_MD_STAT(name, buf);
return rv;
}
#endif /* !defined(WIN16) */
#endif /* ! NO_NSPR_10_SUPPORT */
PR_IMPLEMENT(PRStatus) PR_LockFile(PRFileDesc *fd)
{
PRStatus status = PR_SUCCESS;
#ifdef WINNT
if (!fd->secret->md.io_model_committed) {
PRInt32 rv;
rv = _md_Associate((HANDLE)fd->secret->md.osfd);
PR_ASSERT(0 != rv);
fd->secret->md.io_model_committed = PR_TRUE;
}
#endif
PR_Lock(_pr_flock_lock);
while (fd->secret->lockCount == -1)
PR_WaitCondVar(_pr_flock_cv, PR_INTERVAL_NO_TIMEOUT);
if (fd->secret->lockCount == 0) {
fd->secret->lockCount = -1;
PR_Unlock(_pr_flock_lock);
status = _PR_MD_LOCKFILE(fd->secret->md.osfd);
PR_Lock(_pr_flock_lock);
fd->secret->lockCount = (status == PR_SUCCESS) ? 1 : 0;
PR_NotifyAllCondVar(_pr_flock_cv);
} else {
fd->secret->lockCount++;
}
PR_Unlock(_pr_flock_lock);
return status;
}
PR_IMPLEMENT(PRStatus) PR_TLockFile(PRFileDesc *fd)
{
PRStatus status = PR_SUCCESS;
#ifdef WINNT
if (!fd->secret->md.io_model_committed) {
PRInt32 rv;
rv = _md_Associate((HANDLE)fd->secret->md.osfd);
PR_ASSERT(0 != rv);
fd->secret->md.io_model_committed = PR_TRUE;
}
#endif
PR_Lock(_pr_flock_lock);
if (fd->secret->lockCount == 0) {
status = _PR_MD_TLOCKFILE(fd->secret->md.osfd);
PR_ASSERT(status == PR_SUCCESS || fd->secret->lockCount == 0);
if (status == PR_SUCCESS)
fd->secret->lockCount = 1;
} else {
fd->secret->lockCount++;
}
PR_Unlock(_pr_flock_lock);
return status;
}
PR_IMPLEMENT(PRStatus) PR_UnlockFile(PRFileDesc *fd)
{
PRStatus rv = PR_SUCCESS;
PR_Lock(_pr_flock_lock);
if (fd->secret->lockCount == 1) {
rv = _PR_MD_UNLOCKFILE(fd->secret->md.osfd);
if (rv == PR_SUCCESS)
fd->secret->lockCount = 0;
} else {
fd->secret->lockCount--;
}
PR_Unlock(_pr_flock_lock);
return rv;
}
PR_IMPLEMENT(PRStatus) PR_CreatePipe(
PRFileDesc **readPipe,
PRFileDesc **writePipe
)
{
#if defined(XP_MAC)
#pragma unused (readPipe, writePipe)
#endif
#ifdef WIN32
HANDLE readEnd, writeEnd;
SECURITY_ATTRIBUTES pipeAttributes;
if (!_pr_initialized) _PR_ImplicitInitialization();
ZeroMemory(&pipeAttributes, sizeof(pipeAttributes));
pipeAttributes.nLength = sizeof(pipeAttributes);
pipeAttributes.bInheritHandle = TRUE;
if (CreatePipe(&readEnd, &writeEnd, &pipeAttributes, 0) == 0) {
PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
return PR_FAILURE;
}
*readPipe = PR_AllocFileDesc((PROsfd)readEnd, &_pr_pipeMethods);
if (NULL == *readPipe) {
CloseHandle(readEnd);
CloseHandle(writeEnd);
return PR_FAILURE;
}
*writePipe = PR_AllocFileDesc((PROsfd)writeEnd, &_pr_pipeMethods);
if (NULL == *writePipe) {
PR_Close(*readPipe);
CloseHandle(writeEnd);
return PR_FAILURE;
}
#ifdef WINNT
(*readPipe)->secret->md.sync_file_io = PR_TRUE;
(*writePipe)->secret->md.sync_file_io = PR_TRUE;
#endif
(*readPipe)->secret->inheritable = _PR_TRI_TRUE;
(*writePipe)->secret->inheritable = _PR_TRI_TRUE;
return PR_SUCCESS;
#elif defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
#ifdef XP_OS2
HFILE pipefd[2];
#else
int pipefd[2];
#endif
if (!_pr_initialized) _PR_ImplicitInitialization();
#ifdef XP_OS2
if (DosCreatePipe(&pipefd[0], &pipefd[1], 4096) != 0) {
#else
if (pipe(pipefd) == -1) {
#endif
/* XXX map pipe error */
PR_SetError(PR_UNKNOWN_ERROR, errno);
return PR_FAILURE;
}
*readPipe = PR_AllocFileDesc(pipefd[0], &_pr_pipeMethods);
if (NULL == *readPipe) {
close(pipefd[0]);
close(pipefd[1]);
return PR_FAILURE;
}
*writePipe = PR_AllocFileDesc(pipefd[1], &_pr_pipeMethods);
if (NULL == *writePipe) {
PR_Close(*readPipe);
close(pipefd[1]);
return PR_FAILURE;
}
#ifndef XP_BEOS /* Pipes are nonblocking on BeOS */
_PR_MD_MAKE_NONBLOCK(*readPipe);
#endif
_PR_MD_INIT_FD_INHERITABLE(*readPipe, PR_FALSE);
#ifndef XP_BEOS /* Pipes are nonblocking on BeOS */
_PR_MD_MAKE_NONBLOCK(*writePipe);
#endif
_PR_MD_INIT_FD_INHERITABLE(*writePipe, PR_FALSE);
return PR_SUCCESS;
#else
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
return PR_FAILURE;
#endif
}
#ifdef MOZ_UNICODE
/* ================ UTF16 Interfaces ================================ */
PR_IMPLEMENT(PRFileDesc*) PR_OpenFileUTF16(
const PRUnichar *name, PRIntn flags, PRIntn mode)
{
PROsfd osfd;
PRFileDesc *fd = 0;
#if !defined(_PR_HAVE_O_APPEND)
PRBool appendMode = ( PR_APPEND & flags )? PR_TRUE : PR_FALSE;
#endif
if (!_pr_initialized) _PR_ImplicitInitialization();
/* Map pr open flags and mode to os specific flags */
osfd = _PR_MD_OPEN_FILE_UTF16(name, flags, mode);
if (osfd != -1) {
fd = PR_AllocFileDesc(osfd, &_pr_fileMethods);
if (!fd) {
(void) _PR_MD_CLOSE_FILE(osfd);
} else {
#if !defined(_PR_HAVE_O_APPEND)
fd->secret->appendMode = appendMode;
#endif
_PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE);
}
}
return fd;
}
PR_IMPLEMENT(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info)
{
#ifdef XP_MAC
#pragma unused (fn, info)
#endif
PRInt32 rv;
if (!_pr_initialized) _PR_ImplicitInitialization();
rv = _PR_MD_GETFILEINFO64_UTF16(fn, info);
if (rv < 0) {
return PR_FAILURE;
} else {
return PR_SUCCESS;
}
}
/* ================ UTF16 Interfaces ================================ */
#endif /* MOZ_UNICODE */
+202
View File
@@ -0,0 +1,202 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape Portable Runtime (NSPR).
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "primpl.h"
#include <string.h> /* for memset() */
/************************************************************************/
PRLock *_pr_flock_lock;
PRCondVar *_pr_flock_cv;
void _PR_InitIO(void)
{
const PRIOMethods *methods = PR_GetFileMethods();
_PR_InitFdCache();
_pr_flock_lock = PR_NewLock();
_pr_flock_cv = PR_NewCondVar(_pr_flock_lock);
#ifdef WIN32
_pr_stdin = PR_AllocFileDesc((PROsfd)GetStdHandle(STD_INPUT_HANDLE),
methods);
_pr_stdout = PR_AllocFileDesc((PROsfd)GetStdHandle(STD_OUTPUT_HANDLE),
methods);
_pr_stderr = PR_AllocFileDesc((PROsfd)GetStdHandle(STD_ERROR_HANDLE),
methods);
#ifdef WINNT
_pr_stdin->secret->md.sync_file_io = PR_TRUE;
_pr_stdout->secret->md.sync_file_io = PR_TRUE;
_pr_stderr->secret->md.sync_file_io = PR_TRUE;
#endif
#else
_pr_stdin = PR_AllocFileDesc(0, methods);
_pr_stdout = PR_AllocFileDesc(1, methods);
_pr_stderr = PR_AllocFileDesc(2, methods);
#endif
_PR_MD_INIT_FD_INHERITABLE(_pr_stdin, PR_TRUE);
_PR_MD_INIT_FD_INHERITABLE(_pr_stdout, PR_TRUE);
_PR_MD_INIT_FD_INHERITABLE(_pr_stderr, PR_TRUE);
_PR_MD_INIT_IO();
}
void _PR_CleanupIO(void)
{
PR_FreeFileDesc(_pr_stdin);
_pr_stdin = NULL;
PR_FreeFileDesc(_pr_stdout);
_pr_stdout = NULL;
PR_FreeFileDesc(_pr_stderr);
_pr_stderr = NULL;
if (_pr_flock_cv) {
PR_DestroyCondVar(_pr_flock_cv);
_pr_flock_cv = NULL;
}
if (_pr_flock_lock) {
PR_DestroyLock(_pr_flock_lock);
_pr_flock_lock = NULL;
}
_PR_CleanupFdCache();
}
PR_IMPLEMENT(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD osfd)
{
PRFileDesc *result = NULL;
PR_ASSERT((int) osfd >= PR_StandardInput && osfd <= PR_StandardError);
if (!_pr_initialized) _PR_ImplicitInitialization();
switch (osfd)
{
case PR_StandardInput: result = _pr_stdin; break;
case PR_StandardOutput: result = _pr_stdout; break;
case PR_StandardError: result = _pr_stderr; break;
default:
(void)PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
}
return result;
}
PR_IMPLEMENT(PRFileDesc*) PR_AllocFileDesc(
PROsfd osfd, const PRIOMethods *methods)
{
PRFileDesc *fd;
#ifdef XP_UNIX
/*
* Assert that the file descriptor is small enough to fit in the
* fd_set passed to select
*/
PR_ASSERT(osfd < FD_SETSIZE);
#endif
fd = _PR_Getfd();
if (fd) {
/* Initialize the members of PRFileDesc and PRFilePrivate */
fd->methods = methods;
fd->secret->state = _PR_FILEDESC_OPEN;
fd->secret->md.osfd = osfd;
_PR_MD_INIT_FILEDESC(fd);
} else {
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
}
return fd;
}
PR_IMPLEMENT(void) PR_FreeFileDesc(PRFileDesc *fd)
{
PR_ASSERT(fd);
#ifdef XP_MAC
_PR_MD_FREE_FILEDESC(fd);
#endif
_PR_Putfd(fd);
}
/*
** Wait for some i/o to finish on one or more more poll descriptors.
*/
PR_IMPLEMENT(PRInt32) PR_Poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
{
return(_PR_MD_PR_POLL(pds, npds, timeout));
}
/*
** Set the inheritance attribute of a file descriptor.
*/
PR_IMPLEMENT(PRStatus) PR_SetFDInheritable(
PRFileDesc *fd,
PRBool inheritable)
{
#if defined(XP_UNIX) || defined(WIN32) || defined(XP_OS2) || defined(XP_BEOS)
/*
* Only a non-layered, NSPR file descriptor can be inherited
* by a child process.
*/
if (fd->identity != PR_NSPR_IO_LAYER) {
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
return PR_FAILURE;
}
if (fd->secret->inheritable != inheritable) {
if (_PR_MD_SET_FD_INHERITABLE(fd, inheritable) == PR_FAILURE) {
return PR_FAILURE;
}
fd->secret->inheritable = inheritable;
}
return PR_SUCCESS;
#else
#ifdef XP_MAC
#pragma unused (fd, inheritable)
#endif
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
return PR_FAILURE;
#endif
}
/*
** This function only has a useful implementation in the debug build of
** the pthreads version.
*/
PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg)
{
/* do nothing */
} /* PT_FPrintStats */
+628
View File
@@ -0,0 +1,628 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape Portable Runtime (NSPR).
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "primpl.h"
#include <string.h>
/*****************************************************************************/
/************************** Invalid I/O method object ************************/
/*****************************************************************************/
PRIOMethods _pr_faulty_methods = {
(PRDescType)0,
(PRCloseFN)_PR_InvalidStatus,
(PRReadFN)_PR_InvalidInt,
(PRWriteFN)_PR_InvalidInt,
(PRAvailableFN)_PR_InvalidInt,
(PRAvailable64FN)_PR_InvalidInt64,
(PRFsyncFN)_PR_InvalidStatus,
(PRSeekFN)_PR_InvalidInt,
(PRSeek64FN)_PR_InvalidInt64,
(PRFileInfoFN)_PR_InvalidStatus,
(PRFileInfo64FN)_PR_InvalidStatus,
(PRWritevFN)_PR_InvalidInt,
(PRConnectFN)_PR_InvalidStatus,
(PRAcceptFN)_PR_InvalidDesc,
(PRBindFN)_PR_InvalidStatus,
(PRListenFN)_PR_InvalidStatus,
(PRShutdownFN)_PR_InvalidStatus,
(PRRecvFN)_PR_InvalidInt,
(PRSendFN)_PR_InvalidInt,
(PRRecvfromFN)_PR_InvalidInt,
(PRSendtoFN)_PR_InvalidInt,
(PRPollFN)_PR_InvalidInt16,
(PRAcceptreadFN)_PR_InvalidInt,
(PRTransmitfileFN)_PR_InvalidInt,
(PRGetsocknameFN)_PR_InvalidStatus,
(PRGetpeernameFN)_PR_InvalidStatus,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt,
(PRGetsocketoptionFN)_PR_InvalidStatus,
(PRSetsocketoptionFN)_PR_InvalidStatus,
(PRSendfileFN)_PR_InvalidInt,
(PRConnectcontinueFN)_PR_InvalidStatus,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt
};
PRIntn _PR_InvalidInt(void)
{
PR_ASSERT(!"I/O method is invalid");
PR_SetError(PR_INVALID_METHOD_ERROR, 0);
return -1;
} /* _PR_InvalidInt */
PRInt16 _PR_InvalidInt16(void)
{
PR_ASSERT(!"I/O method is invalid");
PR_SetError(PR_INVALID_METHOD_ERROR, 0);
return -1;
} /* _PR_InvalidInt */
PRInt64 _PR_InvalidInt64(void)
{
PRInt64 rv;
LL_I2L(rv, -1);
PR_ASSERT(!"I/O method is invalid");
PR_SetError(PR_INVALID_METHOD_ERROR, 0);
return rv;
} /* _PR_InvalidInt */
/*
* An invalid method that returns PRStatus
*/
PRStatus _PR_InvalidStatus(void)
{
PR_ASSERT(!"I/O method is invalid");
PR_SetError(PR_INVALID_METHOD_ERROR, 0);
return PR_FAILURE;
} /* _PR_InvalidDesc */
/*
* An invalid method that returns a pointer
*/
PRFileDesc *_PR_InvalidDesc(void)
{
PR_ASSERT(!"I/O method is invalid");
PR_SetError(PR_INVALID_METHOD_ERROR, 0);
return NULL;
} /* _PR_InvalidDesc */
PR_IMPLEMENT(PRDescType) PR_GetDescType(PRFileDesc *file)
{
return file->methods->file_type;
}
PR_IMPLEMENT(PRStatus) PR_Close(PRFileDesc *fd)
{
return (fd->methods->close)(fd);
}
PR_IMPLEMENT(PRInt32) PR_Read(PRFileDesc *fd, void *buf, PRInt32 amount)
{
return((fd->methods->read)(fd,buf,amount));
}
PR_IMPLEMENT(PRInt32) PR_Write(PRFileDesc *fd, const void *buf, PRInt32 amount)
{
return((fd->methods->write)(fd,buf,amount));
}
PR_IMPLEMENT(PRInt32) PR_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence)
{
return((fd->methods->seek)(fd, offset, whence));
}
PR_IMPLEMENT(PRInt64) PR_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence)
{
return((fd->methods->seek64)(fd, offset, whence));
}
PR_IMPLEMENT(PRInt32) PR_Available(PRFileDesc *fd)
{
return((fd->methods->available)(fd));
}
PR_IMPLEMENT(PRInt64) PR_Available64(PRFileDesc *fd)
{
return((fd->methods->available64)(fd));
}
PR_IMPLEMENT(PRStatus) PR_GetOpenFileInfo(PRFileDesc *fd, PRFileInfo *info)
{
return((fd->methods->fileInfo)(fd, info));
}
PR_IMPLEMENT(PRStatus) PR_GetOpenFileInfo64(PRFileDesc *fd, PRFileInfo64 *info)
{
return((fd->methods->fileInfo64)(fd, info));
}
PR_IMPLEMENT(PRStatus) PR_Sync(PRFileDesc *fd)
{
return((fd->methods->fsync)(fd));
}
PR_IMPLEMENT(PRStatus) PR_Connect(
PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
{
return((fd->methods->connect)(fd,addr,timeout));
}
PR_IMPLEMENT(PRStatus) PR_ConnectContinue(
PRFileDesc *fd, PRInt16 out_flags)
{
return((fd->methods->connectcontinue)(fd,out_flags));
}
PR_IMPLEMENT(PRFileDesc*) PR_Accept(PRFileDesc *fd, PRNetAddr *addr,
PRIntervalTime timeout)
{
return((fd->methods->accept)(fd,addr,timeout));
}
PR_IMPLEMENT(PRStatus) PR_Bind(PRFileDesc *fd, const PRNetAddr *addr)
{
return((fd->methods->bind)(fd,addr));
}
PR_IMPLEMENT(PRStatus) PR_Shutdown(PRFileDesc *fd, PRShutdownHow how)
{
return((fd->methods->shutdown)(fd,how));
}
PR_IMPLEMENT(PRStatus) PR_Listen(PRFileDesc *fd, PRIntn backlog)
{
return((fd->methods->listen)(fd,backlog));
}
PR_IMPLEMENT(PRInt32) PR_Recv(PRFileDesc *fd, void *buf, PRInt32 amount,
PRIntn flags, PRIntervalTime timeout)
{
return((fd->methods->recv)(fd,buf,amount,flags,timeout));
}
PR_IMPLEMENT(PRInt32) PR_Send(PRFileDesc *fd, const void *buf, PRInt32 amount,
PRIntn flags, PRIntervalTime timeout)
{
return((fd->methods->send)(fd,buf,amount,flags,timeout));
}
PR_IMPLEMENT(PRInt32) PR_Writev(PRFileDesc *fd, const PRIOVec *iov,
PRInt32 iov_size, PRIntervalTime timeout)
{
if (iov_size > PR_MAX_IOVECTOR_SIZE)
{
PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
return -1;
}
return((fd->methods->writev)(fd,iov,iov_size,timeout));
}
PR_IMPLEMENT(PRInt32) PR_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
{
return((fd->methods->recvfrom)(fd,buf,amount,flags,addr,timeout));
}
PR_IMPLEMENT(PRInt32) PR_SendTo(
PRFileDesc *fd, const void *buf, PRInt32 amount,
PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
{
return((fd->methods->sendto)(fd,buf,amount,flags,addr,timeout));
}
PR_IMPLEMENT(PRInt32) PR_TransmitFile(
PRFileDesc *sd, PRFileDesc *fd, const void *hdr, PRInt32 hlen,
PRTransmitFileFlags flags, PRIntervalTime timeout)
{
return((sd->methods->transmitfile)(sd,fd,hdr,hlen,flags,timeout));
}
PR_IMPLEMENT(PRInt32) PR_AcceptRead(
PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr,
void *buf, PRInt32 amount, PRIntervalTime timeout)
{
return((sd->methods->acceptread)(sd, nd, raddr, buf, amount,timeout));
}
PR_IMPLEMENT(PRStatus) PR_GetSockName(PRFileDesc *fd, PRNetAddr *addr)
{
return((fd->methods->getsockname)(fd,addr));
}
PR_IMPLEMENT(PRStatus) PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
{
return((fd->methods->getpeername)(fd,addr));
}
PR_IMPLEMENT(PRStatus) PR_GetSocketOption(
PRFileDesc *fd, PRSocketOptionData *data)
{
return((fd->methods->getsocketoption)(fd, data));
}
PR_IMPLEMENT(PRStatus) PR_SetSocketOption(
PRFileDesc *fd, const PRSocketOptionData *data)
{
return((fd->methods->setsocketoption)(fd, data));
}
PR_IMPLEMENT(PRInt32) PR_SendFile(
PRFileDesc *sd, PRSendFileData *sfd,
PRTransmitFileFlags flags, PRIntervalTime timeout)
{
return((sd->methods->sendfile)(sd,sfd,flags,timeout));
}
PR_IMPLEMENT(PRInt32) PR_EmulateAcceptRead(
PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr,
void *buf, PRInt32 amount, PRIntervalTime timeout)
{
PRInt32 rv = -1;
PRNetAddr remote;
PRFileDesc *accepted = NULL;
/*
** The timeout does not apply to the accept portion of the
** operation - it waits indefinitely.
*/
accepted = PR_Accept(sd, &remote, PR_INTERVAL_NO_TIMEOUT);
if (NULL == accepted) return rv;
rv = PR_Recv(accepted, buf, amount, 0, timeout);
if (rv >= 0)
{
/* copy the new info out where caller can see it */
#define AMASK ((PRPtrdiff)7) /* mask for alignment of PRNetAddr */
PRPtrdiff aligned = (PRPtrdiff)buf + amount + AMASK;
*raddr = (PRNetAddr*)(aligned & ~AMASK);
memcpy(*raddr, &remote, PR_NETADDR_SIZE(&remote));
*nd = accepted;
return rv;
}
PR_Close(accepted);
return rv;
}
/*
* PR_EmulateSendFile
*
* Send file sfd->fd across socket sd. If header/trailer are specified
* they are sent before and after the file, respectively.
*
* PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
*
* return number of bytes sent or -1 on error
*
*/
#if defined(XP_UNIX) || defined(WIN32)
/*
* An implementation based on memory-mapped files
*/
#define SENDFILE_MMAP_CHUNK (256 * 1024)
PR_IMPLEMENT(PRInt32) PR_EmulateSendFile(
PRFileDesc *sd, PRSendFileData *sfd,
PRTransmitFileFlags flags, PRIntervalTime timeout)
{
PRInt32 rv, count = 0;
PRInt32 len, file_bytes, index = 0;
PRFileInfo info;
PRIOVec iov[3];
PRFileMap *mapHandle = NULL;
void *addr = (void*)0; /* initialized to some arbitrary value. Keeps compiler warnings down. */
PRUint32 file_mmap_offset, alignment;
PRInt64 zero64;
PROffset64 file_mmap_offset64;
PRUint32 addr_offset, mmap_len;
/* Get file size */
if (PR_SUCCESS != PR_GetOpenFileInfo(sfd->fd, &info)) {
count = -1;
goto done;
}
if (sfd->file_nbytes &&
(info.size < (sfd->file_offset + sfd->file_nbytes))) {
/*
* there are fewer bytes in file to send than specified
*/
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
count = -1;
goto done;
}
if (sfd->file_nbytes)
file_bytes = sfd->file_nbytes;
else
file_bytes = info.size - sfd->file_offset;
alignment = PR_GetMemMapAlignment();
/* number of initial bytes to skip in mmap'd segment */
addr_offset = sfd->file_offset % alignment;
/* find previous mmap alignment boundary */
file_mmap_offset = sfd->file_offset - addr_offset;
/*
* If the file is large, mmap and send the file in chunks so as
* to not consume too much virtual address space
*/
mmap_len = PR_MIN(file_bytes + addr_offset, SENDFILE_MMAP_CHUNK);
len = mmap_len - addr_offset;
/*
* Map in (part of) file. Take care of zero-length files.
*/
if (len) {
LL_I2L(zero64, 0);
mapHandle = PR_CreateFileMap(sfd->fd, zero64, PR_PROT_READONLY);
if (!mapHandle) {
count = -1;
goto done;
}
LL_I2L(file_mmap_offset64, file_mmap_offset);
addr = PR_MemMap(mapHandle, file_mmap_offset64, mmap_len);
if (!addr) {
count = -1;
goto done;
}
}
/*
* send headers first, followed by the file
*/
if (sfd->hlen) {
iov[index].iov_base = (char *) sfd->header;
iov[index].iov_len = sfd->hlen;
index++;
}
if (len) {
iov[index].iov_base = (char*)addr + addr_offset;
iov[index].iov_len = len;
index++;
}
if ((file_bytes == len) && (sfd->tlen)) {
/*
* all file data is mapped in; send the trailer too
*/
iov[index].iov_base = (char *) sfd->trailer;
iov[index].iov_len = sfd->tlen;
index++;
}
rv = PR_Writev(sd, iov, index, timeout);
if (len)
PR_MemUnmap(addr, mmap_len);
if (rv < 0) {
count = -1;
goto done;
}
PR_ASSERT(rv == sfd->hlen + len + ((len == file_bytes) ? sfd->tlen : 0));
file_bytes -= len;
count += rv;
if (!file_bytes) /* header, file and trailer are sent */
goto done;
/*
* send remaining bytes of the file, if any
*/
len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK);
while (len > 0) {
/*
* Map in (part of) file
*/
file_mmap_offset = sfd->file_offset + count - sfd->hlen;
PR_ASSERT((file_mmap_offset % alignment) == 0);
LL_I2L(file_mmap_offset64, file_mmap_offset);
addr = PR_MemMap(mapHandle, file_mmap_offset64, len);
if (!addr) {
count = -1;
goto done;
}
rv = PR_Send(sd, addr, len, 0, timeout);
PR_MemUnmap(addr, len);
if (rv < 0) {
count = -1;
goto done;
}
PR_ASSERT(rv == len);
file_bytes -= rv;
count += rv;
len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK);
}
PR_ASSERT(0 == file_bytes);
if (sfd->tlen) {
rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout);
if (rv >= 0) {
PR_ASSERT(rv == sfd->tlen);
count += rv;
} else
count = -1;
}
done:
if (mapHandle)
PR_CloseFileMap(mapHandle);
if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET))
PR_Close(sd);
return count;
}
#else
PR_IMPLEMENT(PRInt32) PR_EmulateSendFile(
PRFileDesc *sd, PRSendFileData *sfd,
PRTransmitFileFlags flags, PRIntervalTime timeout)
{
PRInt32 rv, count = 0;
PRInt32 rlen;
const void * buffer;
PRInt32 buflen;
PRInt32 sendbytes, readbytes;
char *buf;
#define _SENDFILE_BUFSIZE (16 * 1024)
buf = (char*)PR_MALLOC(_SENDFILE_BUFSIZE);
if (buf == NULL) {
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
return -1;
}
/*
* send header first
*/
buflen = sfd->hlen;
buffer = sfd->header;
while (buflen) {
rv = PR_Send(sd, buffer, buflen, 0, timeout);
if (rv < 0) {
/* PR_Send() has invoked PR_SetError(). */
rv = -1;
goto done;
} else {
count += rv;
buffer = (const void*) ((const char*)buffer + rv);
buflen -= rv;
}
}
/*
* send file next
*/
if (PR_Seek(sfd->fd, sfd->file_offset, PR_SEEK_SET) < 0) {
rv = -1;
goto done;
}
sendbytes = sfd->file_nbytes;
if (sendbytes == 0) {
/* send entire file */
while ((rlen = PR_Read(sfd->fd, buf, _SENDFILE_BUFSIZE)) > 0) {
while (rlen) {
char *bufptr = buf;
rv = PR_Send(sd, bufptr, rlen, 0, timeout);
if (rv < 0) {
/* PR_Send() has invoked PR_SetError(). */
rv = -1;
goto done;
} else {
count += rv;
bufptr = ((char*)bufptr + rv);
rlen -= rv;
}
}
}
if (rlen < 0) {
/* PR_Read() has invoked PR_SetError(). */
rv = -1;
goto done;
}
} else {
readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE);
while (readbytes && ((rlen = PR_Read(sfd->fd, buf, readbytes)) > 0)) {
while (rlen) {
char *bufptr = buf;
rv = PR_Send(sd, bufptr, rlen, 0, timeout);
if (rv < 0) {
/* PR_Send() has invoked PR_SetError(). */
rv = -1;
goto done;
} else {
count += rv;
sendbytes -= rv;
bufptr = ((char*)bufptr + rv);
rlen -= rv;
}
}
readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE);
}
if (rlen < 0) {
/* PR_Read() has invoked PR_SetError(). */
rv = -1;
goto done;
} else if (sendbytes != 0) {
/*
* there are fewer bytes in file to send than specified
*/
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
rv = -1;
goto done;
}
}
/*
* send trailer last
*/
buflen = sfd->tlen;
buffer = sfd->trailer;
while (buflen) {
rv = PR_Send(sd, buffer, buflen, 0, timeout);
if (rv < 0) {
/* PR_Send() has invoked PR_SetError(). */
rv = -1;
goto done;
} else {
count += rv;
buffer = (const void*) ((const char*)buffer + rv);
buflen -= rv;
}
}
rv = count;
done:
if (buf)
PR_DELETE(buf);
if ((rv >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET))
PR_Close(sd);
return rv;
}
#endif
/* priometh.c */
+382
View File
@@ -0,0 +1,382 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape Portable Runtime (NSPR).
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
** File: pripv6.c
** Description: Support for various functions unique to IPv6
*/
#include "primpl.h"
#include <string.h>
#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
static PRIOMethods ipv6_to_v4_tcpMethods;
static PRIOMethods ipv6_to_v4_udpMethods;
static PRDescIdentity _pr_ipv6_to_ipv4_id;
extern PRBool IsValidNetAddr(const PRNetAddr *addr);
extern PRIPv6Addr _pr_in6addr_any;
extern PRIPv6Addr _pr_in6addr_loopback;
/*
* convert an IPv4-mapped IPv6 addr to an IPv4 addr
*/
static void _PR_ConvertToIpv4NetAddr(const PRNetAddr *src_v6addr,
PRNetAddr *dst_v4addr)
{
const PRUint8 *srcp;
PR_ASSERT(PR_AF_INET6 == src_v6addr->ipv6.family);
if (PR_IsNetAddrType(src_v6addr, PR_IpAddrV4Mapped)) {
srcp = src_v6addr->ipv6.ip.pr_s6_addr;
memcpy((char *) &dst_v4addr->inet.ip, srcp + 12, 4);
} else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrAny)) {
dst_v4addr->inet.ip = htonl(INADDR_ANY);
} else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrLoopback)) {
dst_v4addr->inet.ip = htonl(INADDR_LOOPBACK);
}
dst_v4addr->inet.family = PR_AF_INET;
dst_v4addr->inet.port = src_v6addr->ipv6.port;
}
/*
* convert an IPv4 addr to an IPv4-mapped IPv6 addr
*/
static void _PR_ConvertToIpv6NetAddr(const PRNetAddr *src_v4addr,
PRNetAddr *dst_v6addr)
{
PRUint8 *dstp;
PR_ASSERT(PR_AF_INET == src_v4addr->inet.family);
dst_v6addr->ipv6.family = PR_AF_INET6;
dst_v6addr->ipv6.port = src_v4addr->inet.port;
if (htonl(INADDR_ANY) == src_v4addr->inet.ip) {
dst_v6addr->ipv6.ip = _pr_in6addr_any;
} else {
dstp = dst_v6addr->ipv6.ip.pr_s6_addr;
memset(dstp, 0, 10);
memset(dstp + 10, 0xff, 2);
memcpy(dstp + 12,(char *) &src_v4addr->inet.ip, 4);
}
}
static PRStatus PR_CALLBACK Ipv6ToIpv4SocketBind(PRFileDesc *fd,
const PRNetAddr *addr)
{
PRNetAddr tmp_ipv4addr;
const PRNetAddr *tmp_addrp;
PRFileDesc *lo = fd->lower;
if (PR_AF_INET6 != addr->raw.family) {
PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
return PR_FAILURE;
}
if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
PR_IsNetAddrType(addr, PR_IpAddrAny)) {
_PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
tmp_addrp = &tmp_ipv4addr;
} else {
PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
return PR_FAILURE;
}
return((lo->methods->bind)(lo,tmp_addrp));
}
static PRStatus PR_CALLBACK Ipv6ToIpv4SocketConnect(
PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
{
PRNetAddr tmp_ipv4addr;
const PRNetAddr *tmp_addrp;
if (PR_AF_INET6 != addr->raw.family) {
PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
return PR_FAILURE;
}
if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
PR_IsNetAddrType(addr, PR_IpAddrLoopback)) {
_PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
tmp_addrp = &tmp_ipv4addr;
} else {
PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
return PR_FAILURE;
}
return (fd->lower->methods->connect)(fd->lower, tmp_addrp, timeout);
}
static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketSendTo(
PRFileDesc *fd, const void *buf, PRInt32 amount,
PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
{
PRNetAddr tmp_ipv4addr;
const PRNetAddr *tmp_addrp;
if (PR_AF_INET6 != addr->raw.family) {
PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
return PR_FAILURE;
}
if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
PR_IsNetAddrType(addr, PR_IpAddrLoopback)) {
_PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
tmp_addrp = &tmp_ipv4addr;
} else {
PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
return PR_FAILURE;
}
return (fd->lower->methods->sendto)(
fd->lower, buf, amount, flags, tmp_addrp, timeout);
}
static PRFileDesc* PR_CALLBACK Ipv6ToIpv4SocketAccept (
PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
{
PRStatus rv;
PRFileDesc *newfd;
PRFileDesc *newstack;
PRNetAddr tmp_ipv4addr;
PRNetAddr *addrlower = NULL;
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
newstack = PR_NEW(PRFileDesc);
if (NULL == newstack)
{
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
return NULL;
}
*newstack = *fd; /* make a copy of the accepting layer */
if (addr)
addrlower = &tmp_ipv4addr;
newfd = (fd->lower->methods->accept)(fd->lower, addrlower, timeout);
if (NULL == newfd)
{
PR_DELETE(newstack);
return NULL;
}
if (addr)
_PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, addr);
rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
PR_ASSERT(PR_SUCCESS == rv);
return newfd; /* that's it */
}
static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketAcceptRead(PRFileDesc *sd,
PRFileDesc **nd, PRNetAddr **ipv6_raddr, void *buf, PRInt32 amount,
PRIntervalTime timeout)
{
PRInt32 nbytes;
PRStatus rv;
PRNetAddr tmp_ipv4addr;
PRFileDesc *newstack;
PR_ASSERT(sd != NULL);
PR_ASSERT(sd->lower != NULL);
newstack = PR_NEW(PRFileDesc);
if (NULL == newstack)
{
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
return -1;
}
*newstack = *sd; /* make a copy of the accepting layer */
nbytes = sd->lower->methods->acceptread(
sd->lower, nd, ipv6_raddr, buf, amount, timeout);
if (-1 == nbytes)
{
PR_DELETE(newstack);
return nbytes;
}
tmp_ipv4addr = **ipv6_raddr; /* copy */
_PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, *ipv6_raddr);
/* this PR_PushIOLayer call cannot fail */
rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack);
PR_ASSERT(PR_SUCCESS == rv);
return nbytes;
}
static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetName(PRFileDesc *fd,
PRNetAddr *ipv6addr)
{
PRStatus result;
PRNetAddr tmp_ipv4addr;
result = (fd->lower->methods->getsockname)(fd->lower, &tmp_ipv4addr);
if (PR_SUCCESS == result) {
_PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
}
return result;
}
static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetPeerName(PRFileDesc *fd,
PRNetAddr *ipv6addr)
{
PRStatus result;
PRNetAddr tmp_ipv4addr;
result = (fd->lower->methods->getpeername)(fd->lower, &tmp_ipv4addr);
if (PR_SUCCESS == result) {
_PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
}
return result;
}
static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketRecvFrom(PRFileDesc *fd, void *buf,
PRInt32 amount, PRIntn flags, PRNetAddr *ipv6addr,
PRIntervalTime timeout)
{
PRNetAddr tmp_ipv4addr;
PRInt32 result;
result = (fd->lower->methods->recvfrom)(
fd->lower, buf, amount, flags, &tmp_ipv4addr, timeout);
if (-1 != result) {
_PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
}
return result;
}
#if defined(_PR_INET6_PROBE)
PRBool _pr_ipv6_is_present;
extern PRBool _pr_test_ipv6_socket(void);
#if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
extern PRStatus _pr_find_getipnodebyname(void);
#endif
#if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
extern PRStatus _pr_find_getaddrinfo(void);
#endif
static PRBool
_pr_probe_ipv6_presence(void)
{
#if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
if (_pr_find_getipnodebyname() != PR_SUCCESS)
return PR_FALSE;
#endif
#if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
if (_pr_find_getaddrinfo() != PR_SUCCESS)
return PR_FALSE;
#endif
return _pr_test_ipv6_socket();
}
#endif /* _PR_INET6_PROBE */
PRStatus _pr_init_ipv6()
{
const PRIOMethods *stubMethods;
#if defined(_PR_INET6_PROBE)
_pr_ipv6_is_present = _pr_probe_ipv6_presence();
if (PR_TRUE == _pr_ipv6_is_present)
return PR_SUCCESS;
#endif
_pr_ipv6_to_ipv4_id = PR_GetUniqueIdentity("Ipv6_to_Ipv4 layer");
PR_ASSERT(PR_INVALID_IO_LAYER != _pr_ipv6_to_ipv4_id);
stubMethods = PR_GetDefaultIOMethods();
ipv6_to_v4_tcpMethods = *stubMethods; /* first get the entire batch */
/* then override the ones we care about */
ipv6_to_v4_tcpMethods.connect = Ipv6ToIpv4SocketConnect;
ipv6_to_v4_tcpMethods.bind = Ipv6ToIpv4SocketBind;
ipv6_to_v4_tcpMethods.accept = Ipv6ToIpv4SocketAccept;
ipv6_to_v4_tcpMethods.acceptread = Ipv6ToIpv4SocketAcceptRead;
ipv6_to_v4_tcpMethods.getsockname = Ipv6ToIpv4SocketGetName;
ipv6_to_v4_tcpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName;
/*
ipv6_to_v4_tcpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption;
ipv6_to_v4_tcpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption;
*/
ipv6_to_v4_udpMethods = *stubMethods; /* first get the entire batch */
/* then override the ones we care about */
ipv6_to_v4_udpMethods.connect = Ipv6ToIpv4SocketConnect;
ipv6_to_v4_udpMethods.bind = Ipv6ToIpv4SocketBind;
ipv6_to_v4_udpMethods.sendto = Ipv6ToIpv4SocketSendTo;
ipv6_to_v4_udpMethods.recvfrom = Ipv6ToIpv4SocketRecvFrom;
ipv6_to_v4_udpMethods.getsockname = Ipv6ToIpv4SocketGetName;
ipv6_to_v4_udpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName;
/*
ipv6_to_v4_udpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption;
ipv6_to_v4_udpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption;
*/
return PR_SUCCESS;
}
PR_IMPLEMENT(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd)
{
PRFileDesc *ipv6_fd = NULL;
/*
* For platforms with no support for IPv6
* create layered socket for IPv4-mapped IPv6 addresses
*/
if (fd->methods->file_type == PR_DESC_SOCKET_TCP)
ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id,
&ipv6_to_v4_tcpMethods);
else
ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id,
&ipv6_to_v4_udpMethods);
if (NULL == ipv6_fd) {
goto errorExit;
}
ipv6_fd->secret = NULL;
if (PR_PushIOLayer(fd, PR_TOP_IO_LAYER, ipv6_fd) == PR_FAILURE) {
goto errorExit;
}
return PR_SUCCESS;
errorExit:
if (ipv6_fd)
ipv6_fd->dtor(ipv6_fd);
return PR_FAILURE;
}
#endif /* !defined(_PR_INET6) || defined(_PR_INET6_PROBE) */
+768
View File
@@ -0,0 +1,768 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape Portable Runtime (NSPR).
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
** File: prlayer.c
** Description: Routines for handling pushable protocol modules on sockets.
*/
#include "primpl.h"
#include "prerror.h"
#include "prmem.h"
#include "prlock.h"
#include "prlog.h"
#include "prio.h"
#include <string.h> /* for memset() */
static PRStatus _PR_DestroyIOLayer(PRFileDesc *stack);
void PR_CALLBACK pl_FDDestructor(PRFileDesc *fd)
{
PR_ASSERT(fd != NULL);
if (NULL != fd->lower) fd->lower->higher = fd->higher;
if (NULL != fd->higher) fd->higher->lower = fd->lower;
PR_DELETE(fd);
}
/*
** Default methods that just call down to the next fd.
*/
static PRStatus PR_CALLBACK pl_TopClose (PRFileDesc *fd)
{
PRFileDesc *top, *lower;
PRStatus rv;
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
PR_ASSERT(fd->secret == NULL);
PR_ASSERT(fd->methods->file_type == PR_DESC_LAYERED);
if (PR_IO_LAYER_HEAD == fd->identity) {
/*
* new style stack; close all the layers, before deleting the
* stack head
*/
rv = fd->lower->methods->close(fd->lower);
_PR_DestroyIOLayer(fd);
return rv;
} else if ((fd->higher) && (PR_IO_LAYER_HEAD == fd->higher->identity)) {
/*
* lower layers of new style stack
*/
lower = fd->lower;
/*
* pop and cleanup current layer
*/
top = PR_PopIOLayer(fd->higher, PR_TOP_IO_LAYER);
top->dtor(top);
/*
* then call lower layer
*/
return (lower->methods->close(lower));
} else {
/* old style stack */
top = PR_PopIOLayer(fd, PR_TOP_IO_LAYER);
top->dtor(top);
return (fd->methods->close)(fd);
}
}
static PRInt32 PR_CALLBACK pl_DefRead (PRFileDesc *fd, void *buf, PRInt32 amount)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->read)(fd->lower, buf, amount);
}
static PRInt32 PR_CALLBACK pl_DefWrite (
PRFileDesc *fd, const void *buf, PRInt32 amount)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->write)(fd->lower, buf, amount);
}
static PRInt32 PR_CALLBACK pl_DefAvailable (PRFileDesc *fd)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->available)(fd->lower);
}
static PRInt64 PR_CALLBACK pl_DefAvailable64 (PRFileDesc *fd)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->available64)(fd->lower);
}
static PRStatus PR_CALLBACK pl_DefFsync (PRFileDesc *fd)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->fsync)(fd->lower);
}
static PRInt32 PR_CALLBACK pl_DefSeek (
PRFileDesc *fd, PRInt32 offset, PRSeekWhence how)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->seek)(fd->lower, offset, how);
}
static PRInt64 PR_CALLBACK pl_DefSeek64 (
PRFileDesc *fd, PRInt64 offset, PRSeekWhence how)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->seek64)(fd->lower, offset, how);
}
static PRStatus PR_CALLBACK pl_DefFileInfo (PRFileDesc *fd, PRFileInfo *info)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->fileInfo)(fd->lower, info);
}
static PRStatus PR_CALLBACK pl_DefFileInfo64 (PRFileDesc *fd, PRFileInfo64 *info)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->fileInfo64)(fd->lower, info);
}
static PRInt32 PR_CALLBACK pl_DefWritev (PRFileDesc *fd, const PRIOVec *iov,
PRInt32 size, PRIntervalTime timeout)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->writev)(fd->lower, iov, size, timeout);
}
static PRStatus PR_CALLBACK pl_DefConnect (
PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->connect)(fd->lower, addr, timeout);
}
static PRStatus PR_CALLBACK pl_DefConnectcontinue (
PRFileDesc *fd, PRInt16 out_flags)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->connectcontinue)(fd->lower, out_flags);
}
static PRFileDesc* PR_CALLBACK pl_TopAccept (
PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
{
PRStatus rv;
PRFileDesc *newfd, *layer = fd;
PRFileDesc *newstack;
PRBool newstyle_stack = PR_FALSE;
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
/* test for new style stack */
while (NULL != layer->higher)
layer = layer->higher;
newstyle_stack = (PR_IO_LAYER_HEAD == layer->identity) ? PR_TRUE : PR_FALSE;
newstack = PR_NEW(PRFileDesc);
if (NULL == newstack)
{
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
return NULL;
}
*newstack = *fd; /* make a copy of the accepting layer */
newfd = (fd->lower->methods->accept)(fd->lower, addr, timeout);
if (NULL == newfd)
{
PR_DELETE(newstack);
return NULL;
}
if (newstyle_stack) {
newstack->lower = newfd;
newfd->higher = newstack;
return newstack;
} else {
/* this PR_PushIOLayer call cannot fail */
rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
PR_ASSERT(PR_SUCCESS == rv);
return newfd; /* that's it */
}
}
static PRStatus PR_CALLBACK pl_DefBind (PRFileDesc *fd, const PRNetAddr *addr)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->bind)(fd->lower, addr);
}
static PRStatus PR_CALLBACK pl_DefListen (PRFileDesc *fd, PRIntn backlog)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->listen)(fd->lower, backlog);
}
static PRStatus PR_CALLBACK pl_DefShutdown (PRFileDesc *fd, PRIntn how)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->shutdown)(fd->lower, how);
}
static PRInt32 PR_CALLBACK pl_DefRecv (
PRFileDesc *fd, void *buf, PRInt32 amount,
PRIntn flags, PRIntervalTime timeout)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->recv)(
fd->lower, buf, amount, flags, timeout);
}
static PRInt32 PR_CALLBACK pl_DefSend (
PRFileDesc *fd, const void *buf,
PRInt32 amount, PRIntn flags, PRIntervalTime timeout)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->send)(fd->lower, buf, amount, flags, timeout);
}
static PRInt32 PR_CALLBACK pl_DefRecvfrom (
PRFileDesc *fd, void *buf, PRInt32 amount,
PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->recvfrom)(
fd->lower, buf, amount, flags, addr, timeout);
}
static PRInt32 PR_CALLBACK pl_DefSendto (
PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
const PRNetAddr *addr, PRIntervalTime timeout)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->sendto)(
fd->lower, buf, amount, flags, addr, timeout);
}
static PRInt16 PR_CALLBACK pl_DefPoll (
PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->poll)(fd->lower, in_flags, out_flags);
}
static PRInt32 PR_CALLBACK pl_DefAcceptread (
PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, void *buf,
PRInt32 amount, PRIntervalTime t)
{
PRInt32 nbytes;
PRStatus rv;
PRFileDesc *newstack;
PRFileDesc *layer = sd;
PRBool newstyle_stack = PR_FALSE;
PR_ASSERT(sd != NULL);
PR_ASSERT(sd->lower != NULL);
/* test for new style stack */
while (NULL != layer->higher)
layer = layer->higher;
newstyle_stack = (PR_IO_LAYER_HEAD == layer->identity) ? PR_TRUE : PR_FALSE;
newstack = PR_NEW(PRFileDesc);
if (NULL == newstack)
{
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
return -1;
}
*newstack = *sd; /* make a copy of the accepting layer */
nbytes = sd->lower->methods->acceptread(
sd->lower, nd, raddr, buf, amount, t);
if (-1 == nbytes)
{
PR_DELETE(newstack);
return nbytes;
}
if (newstyle_stack) {
newstack->lower = *nd;
(*nd)->higher = newstack;
*nd = newstack;
return nbytes;
} else {
/* this PR_PushIOLayer call cannot fail */
rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack);
PR_ASSERT(PR_SUCCESS == rv);
return nbytes;
}
}
static PRInt32 PR_CALLBACK pl_DefTransmitfile (
PRFileDesc *sd, PRFileDesc *fd, const void *headers, PRInt32 hlen,
PRTransmitFileFlags flags, PRIntervalTime t)
{
PR_ASSERT(sd != NULL);
PR_ASSERT(sd->lower != NULL);
return sd->lower->methods->transmitfile(
sd->lower, fd, headers, hlen, flags, t);
}
static PRStatus PR_CALLBACK pl_DefGetsockname (PRFileDesc *fd, PRNetAddr *addr)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->getsockname)(fd->lower, addr);
}
static PRStatus PR_CALLBACK pl_DefGetpeername (PRFileDesc *fd, PRNetAddr *addr)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->getpeername)(fd->lower, addr);
}
static PRStatus PR_CALLBACK pl_DefGetsocketoption (
PRFileDesc *fd, PRSocketOptionData *data)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->getsocketoption)(fd->lower, data);
}
static PRStatus PR_CALLBACK pl_DefSetsocketoption (
PRFileDesc *fd, const PRSocketOptionData *data)
{
PR_ASSERT(fd != NULL);
PR_ASSERT(fd->lower != NULL);
return (fd->lower->methods->setsocketoption)(fd->lower, data);
}
static PRInt32 PR_CALLBACK pl_DefSendfile (
PRFileDesc *sd, PRSendFileData *sfd,
PRTransmitFileFlags flags, PRIntervalTime timeout)
{
PR_ASSERT(sd != NULL);
PR_ASSERT(sd->lower != NULL);
return sd->lower->methods->sendfile(
sd->lower, sfd, flags, timeout);
}
/* Methods for the top of the stack. Just call down to the next fd. */
static PRIOMethods pl_methods = {
PR_DESC_LAYERED,
pl_TopClose,
pl_DefRead,
pl_DefWrite,
pl_DefAvailable,
pl_DefAvailable64,
pl_DefFsync,
pl_DefSeek,
pl_DefSeek64,
pl_DefFileInfo,
pl_DefFileInfo64,
pl_DefWritev,
pl_DefConnect,
pl_TopAccept,
pl_DefBind,
pl_DefListen,
pl_DefShutdown,
pl_DefRecv,
pl_DefSend,
pl_DefRecvfrom,
pl_DefSendto,
pl_DefPoll,
pl_DefAcceptread,
pl_DefTransmitfile,
pl_DefGetsockname,
pl_DefGetpeername,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt,
pl_DefGetsocketoption,
pl_DefSetsocketoption,
pl_DefSendfile,
pl_DefConnectcontinue,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt
};
PR_IMPLEMENT(const PRIOMethods*) PR_GetDefaultIOMethods(void)
{
return &pl_methods;
} /* PR_GetDefaultIOMethods */
PR_IMPLEMENT(PRFileDesc*) PR_CreateIOLayerStub(
PRDescIdentity ident, const PRIOMethods *methods)
{
PRFileDesc *fd = NULL;
PR_ASSERT((PR_NSPR_IO_LAYER != ident) && (PR_TOP_IO_LAYER != ident));
if ((PR_NSPR_IO_LAYER == ident) || (PR_TOP_IO_LAYER == ident))
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
else
{
fd = PR_NEWZAP(PRFileDesc);
if (NULL == fd)
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
else
{
fd->methods = methods;
fd->dtor = pl_FDDestructor;
fd->identity = ident;
}
}
return fd;
} /* PR_CreateIOLayerStub */
/*
* PR_CreateIOLayer
* Create a new style stack, where the stack top is a dummy header.
* Unlike the old style stacks, the contents of the stack head
* are not modified when a layer is pushed onto or popped from a new
* style stack.
*/
PR_IMPLEMENT(PRFileDesc*) PR_CreateIOLayer(PRFileDesc *top)
{
PRFileDesc *fd = NULL;
fd = PR_NEWZAP(PRFileDesc);
if (NULL == fd)
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
else
{
fd->methods = &pl_methods;
fd->dtor = pl_FDDestructor;
fd->identity = PR_IO_LAYER_HEAD;
fd->higher = NULL;
fd->lower = top;
top->higher = fd;
top->lower = NULL;
}
return fd;
} /* PR_CreateIOLayer */
/*
* _PR_DestroyIOLayer
* Delete the stack head of a new style stack.
*/
static PRStatus _PR_DestroyIOLayer(PRFileDesc *stack)
{
if (NULL == stack)
return PR_FAILURE;
else {
PR_DELETE(stack);
return PR_SUCCESS;
}
} /* _PR_DestroyIOLayer */
PR_IMPLEMENT(PRStatus) PR_PushIOLayer(
PRFileDesc *stack, PRDescIdentity id, PRFileDesc *fd)
{
PRFileDesc *insert = PR_GetIdentitiesLayer(stack, id);
PR_ASSERT(fd != NULL);
PR_ASSERT(stack != NULL);
PR_ASSERT(insert != NULL);
PR_ASSERT(PR_IO_LAYER_HEAD != id);
if ((NULL == stack) || (NULL == fd) || (NULL == insert))
{
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
return PR_FAILURE;
}
if (stack == insert)
{
/* going on top of the stack */
/* old-style stack */
PRFileDesc copy = *stack;
*stack = *fd;
*fd = copy;
fd->higher = stack;
stack->lower = fd;
stack->higher = NULL;
} else {
/*
* going somewhere in the middle of the stack for both old and new
* style stacks, or going on top of stack for new style stack
*/
fd->lower = insert;
fd->higher = insert->higher;
insert->higher->lower = fd;
insert->higher = fd;
}
return PR_SUCCESS;
}
PR_IMPLEMENT(PRFileDesc*) PR_PopIOLayer(PRFileDesc *stack, PRDescIdentity id)
{
PRFileDesc *extract = PR_GetIdentitiesLayer(stack, id);
PR_ASSERT(0 != id);
PR_ASSERT(NULL != stack);
PR_ASSERT(NULL != extract);
if ((NULL == stack) || (0 == id) || (NULL == extract))
{
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
return NULL;
}
if (extract == stack) {
/* popping top layer of the stack */
/* old style stack */
PRFileDesc copy = *stack;
extract = stack->lower;
*stack = *extract;
*extract = copy;
stack->higher = NULL;
} else if ((PR_IO_LAYER_HEAD == stack->identity) &&
(extract == stack->lower) && (extract->lower == NULL)) {
/*
* new style stack
* popping the only layer in the stack; delete the stack too
*/
stack->lower = NULL;
_PR_DestroyIOLayer(stack);
} else {
/* for both kinds of stacks */
extract->lower->higher = extract->higher;
extract->higher->lower = extract->lower;
}
extract->higher = extract->lower = NULL;
return extract;
} /* PR_PopIOLayer */
#define ID_CACHE_INCREMENT 16
typedef struct _PRIdentity_cache
{
PRLock *ml;
char **name;
PRIntn length;
PRDescIdentity ident;
} _PRIdentity_cache;
static _PRIdentity_cache identity_cache;
PR_IMPLEMENT(PRDescIdentity) PR_GetUniqueIdentity(const char *layer_name)
{
PRDescIdentity identity, length;
char **names = NULL, *name = NULL, **old = NULL;
if (!_pr_initialized) _PR_ImplicitInitialization();
PR_ASSERT((PRDescIdentity)0x7fff > identity_cache.ident);
if (NULL != layer_name)
{
name = (char*)PR_Malloc(strlen(layer_name) + 1);
if (NULL == name)
{
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
return PR_INVALID_IO_LAYER;
}
strcpy(name, layer_name);
}
/* this initial code runs unsafe */
retry:
PR_ASSERT(NULL == names);
length = identity_cache.length;
if (length < (identity_cache.ident + 1))
{
length += ID_CACHE_INCREMENT;
names = (char**)PR_CALLOC(length * sizeof(char*));
if (NULL == names)
{
if (NULL != name) PR_DELETE(name);
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
return PR_INVALID_IO_LAYER;
}
}
/* now we get serious about thread safety */
PR_Lock(identity_cache.ml);
PR_ASSERT(identity_cache.ident <= identity_cache.length);
identity = identity_cache.ident + 1;
if (identity > identity_cache.length) /* there's no room */
{
/* we have to do something - hopefully it's already done */
if ((NULL != names) && (length >= identity))
{
/* what we did is still okay */
memcpy(
names, identity_cache.name,
identity_cache.length * sizeof(char*));
old = identity_cache.name;
identity_cache.name = names;
identity_cache.length = length;
names = NULL;
}
else
{
PR_ASSERT(identity_cache.ident <= identity_cache.length);
PR_Unlock(identity_cache.ml);
if (NULL != names) PR_DELETE(names);
goto retry;
}
}
if (NULL != name) /* there's a name to be stored */
{
identity_cache.name[identity] = name;
}
identity_cache.ident = identity;
PR_ASSERT(identity_cache.ident <= identity_cache.length);
PR_Unlock(identity_cache.ml);
if (NULL != old) PR_DELETE(old);
if (NULL != names) PR_DELETE(names);
return identity;
} /* PR_GetUniqueIdentity */
PR_IMPLEMENT(const char*) PR_GetNameForIdentity(PRDescIdentity ident)
{
if (!_pr_initialized) _PR_ImplicitInitialization();
if (PR_TOP_IO_LAYER == ident) return NULL;
PR_ASSERT(ident <= identity_cache.ident);
return (ident > identity_cache.ident) ? NULL : identity_cache.name[ident];
} /* PR_GetNameForIdentity */
PR_IMPLEMENT(PRDescIdentity) PR_GetLayersIdentity(PRFileDesc* fd)
{
PR_ASSERT(NULL != fd);
if (PR_IO_LAYER_HEAD == fd->identity) {
PR_ASSERT(NULL != fd->lower);
return fd->lower->identity;
} else
return fd->identity;
} /* PR_GetLayersIdentity */
PR_IMPLEMENT(PRFileDesc*) PR_GetIdentitiesLayer(PRFileDesc* fd, PRDescIdentity id)
{
PRFileDesc *layer = fd;
if (PR_TOP_IO_LAYER == id) {
if (PR_IO_LAYER_HEAD == fd->identity)
return fd->lower;
else
return fd;
}
for (layer = fd; layer != NULL; layer = layer->lower)
{
if (id == layer->identity) return layer;
}
for (layer = fd; layer != NULL; layer = layer->higher)
{
if (id == layer->identity) return layer;
}
return NULL;
} /* PR_GetIdentitiesLayer */
void _PR_InitLayerCache(void)
{
memset(&identity_cache, 0, sizeof(identity_cache));
identity_cache.ml = PR_NewLock();
PR_ASSERT(NULL != identity_cache.ml);
} /* _PR_InitLayerCache */
void _PR_CleanupLayerCache(void)
{
if (identity_cache.ml)
{
PR_DestroyLock(identity_cache.ml);
identity_cache.ml = NULL;
}
if (identity_cache.name)
{
PRDescIdentity ident;
for (ident = 0; ident <= identity_cache.ident; ident++)
PR_DELETE(identity_cache.name[ident]);
PR_DELETE(identity_cache.name);
}
} /* _PR_CleanupLayerCache */
/* prlayer.c */
+547
View File
@@ -0,0 +1,547 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape Portable Runtime (NSPR).
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
* Contributors:
*
* This Original Code has been modified by IBM Corporation.
* Modifications made by IBM described herein are
* Copyright (c) International Business Machines Corporation, 2000.
* Modifications to Mozilla code or documentation identified per
* MPL Section 3.3
*
* Date Modified by Description of modification
* 04/10/2000 IBM Corp. Added DebugBreak() definitions for OS/2
*/
#include "primpl.h"
#include "prenv.h"
#include "prprf.h"
#include <string.h>
/*
* Lock used to lock the log.
*
* We can't define _PR_LOCK_LOG simply as PR_Lock because PR_Lock may
* contain assertions. We have to avoid assertions in _PR_LOCK_LOG
* because PR_ASSERT calls PR_LogPrint, which in turn calls _PR_LOCK_LOG.
* This can lead to infinite recursion.
*/
static PRLock *_pr_logLock;
#if defined(_PR_PTHREADS) || defined(_PR_BTHREADS)
#define _PR_LOCK_LOG() PR_Lock(_pr_logLock);
#define _PR_UNLOCK_LOG() PR_Unlock(_pr_logLock);
#elif defined(_PR_GLOBAL_THREADS_ONLY)
#define _PR_LOCK_LOG() { _PR_LOCK_LOCK(_pr_logLock)
#define _PR_UNLOCK_LOG() _PR_LOCK_UNLOCK(_pr_logLock); }
#else
#define _PR_LOCK_LOG() \
{ \
PRIntn _is; \
PRThread *_me = _PR_MD_CURRENT_THREAD(); \
if (!_PR_IS_NATIVE_THREAD(_me)) \
_PR_INTSOFF(_is); \
_PR_LOCK_LOCK(_pr_logLock)
#define _PR_UNLOCK_LOG() \
_PR_LOCK_UNLOCK(_pr_logLock); \
PR_ASSERT(_me == _PR_MD_CURRENT_THREAD()); \
if (!_PR_IS_NATIVE_THREAD(_me)) \
_PR_INTSON(_is); \
}
#endif
#if defined(XP_PC)
#define strcasecmp stricmp
#define strncasecmp strnicmp
#endif
/*
* On NT, we can't define _PUT_LOG as PR_Write or _PR_MD_WRITE,
* because every asynchronous file io operation leads to a fiber context
* switch. So we define _PUT_LOG as fputs (from stdio.h). A side
* benefit is that fputs handles the LF->CRLF translation. This
* code can also be used on other platforms with file stream io.
*/
#if defined(WIN32) || defined(XP_OS2)
#define _PR_USE_STDIO_FOR_LOGGING
#endif
/*
** Coerce Win32 log output to use OutputDebugString() when
** NSPR_LOG_FILE is set to "WinDebug".
*/
#if defined(XP_PC)
#define WIN32_DEBUG_FILE (FILE*)-2
#endif
/* Macros used to reduce #ifdef pollution */
#if defined(_PR_USE_STDIO_FOR_LOGGING) && defined(XP_PC)
#define _PUT_LOG(fd, buf, nb) \
PR_BEGIN_MACRO \
if (logFile == WIN32_DEBUG_FILE) { \
char savebyte = buf[nb]; \
buf[nb] = '\0'; \
OutputDebugString(buf); \
buf[nb] = savebyte; \
} else { \
fwrite(buf, 1, nb, fd); \
fflush(fd); \
} \
PR_END_MACRO
#elif defined(_PR_USE_STDIO_FOR_LOGGING)
#define _PUT_LOG(fd, buf, nb) {fwrite(buf, 1, nb, fd); fflush(fd);}
#elif defined(_PR_PTHREADS)
#define _PUT_LOG(fd, buf, nb) PR_Write(fd, buf, nb)
#elif defined(XP_MAC)
#define _PUT_LOG(fd, buf, nb) _PR_MD_WRITE_SYNC(fd, buf, nb)
#else
#define _PUT_LOG(fd, buf, nb) _PR_MD_WRITE(fd, buf, nb)
#endif
/************************************************************************/
static PRLogModuleInfo *logModules;
static char *logBuf = NULL;
static char *logp;
static char *logEndp;
#ifdef _PR_USE_STDIO_FOR_LOGGING
static FILE *logFile = NULL;
#else
static PRFileDesc *logFile = 0;
#endif
#define LINE_BUF_SIZE 512
#define DEFAULT_BUF_SIZE 16384
#ifdef _PR_NEED_STRCASECMP
/*
* strcasecmp is defined in /usr/ucblib/libucb.a on some platforms
* such as NCR and Unixware. Linking with both libc and libucb
* may cause some problem, so I just provide our own implementation
* of strcasecmp here.
*/
static const unsigned char uc[] =
{
'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
' ', '!', '"', '#', '$', '%', '&', '\'',
'(', ')', '*', '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', ':', ';', '<', '=', '>', '?',
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', '{', '|', '}', '~', '\177'
};
PRIntn strcasecmp(const char *a, const char *b)
{
const unsigned char *ua = (const unsigned char *)a;
const unsigned char *ub = (const unsigned char *)b;
if( ((const char *)0 == a) || (const char *)0 == b )
return (PRIntn)(a-b);
while( (uc[*ua] == uc[*ub]) && ('\0' != *a) )
{
a++;
ua++;
ub++;
}
return (PRIntn)(uc[*ua] - uc[*ub]);
}
#endif /* _PR_NEED_STRCASECMP */
void _PR_InitLog(void)
{
char *ev;
_pr_logLock = PR_NewLock();
ev = PR_GetEnv("NSPR_LOG_MODULES");
if (ev && ev[0]) {
char module[64]; /* Security-Critical: If you change this
* size, you must also change the sscanf
* format string to be size-1.
*/
PRBool isSync = PR_FALSE;
PRIntn evlen = strlen(ev), pos = 0;
PRInt32 bufSize = DEFAULT_BUF_SIZE;
while (pos < evlen) {
PRIntn level = 1, count = 0, delta = 0;
count = sscanf(&ev[pos], "%63[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-]%n:%d%n",
module, &delta, &level, &delta);
pos += delta;
if (count == 0) break;
/*
** If count == 2, then we got module and level. If count
** == 1, then level defaults to 1 (module enabled).
*/
if (strcasecmp(module, "sync") == 0) {
isSync = PR_TRUE;
} else if (strcasecmp(module, "bufsize") == 0) {
if (level >= LINE_BUF_SIZE) {
bufSize = level;
}
} else {
PRLogModuleInfo *lm = logModules;
PRBool skip_modcheck =
(0 == strcasecmp (module, "all")) ? PR_TRUE : PR_FALSE;
while (lm != NULL) {
if (skip_modcheck) lm -> level = (PRLogModuleLevel)level;
else if (strcasecmp(module, lm->name) == 0) {
lm->level = (PRLogModuleLevel)level;
break;
}
lm = lm->next;
}
}
/*found:*/
count = sscanf(&ev[pos], " , %n", &delta);
pos += delta;
if (count == EOF) break;
}
PR_SetLogBuffering(isSync ? bufSize : 0);
ev = PR_GetEnv("NSPR_LOG_FILE");
if (ev && ev[0]) {
if (!PR_SetLogFile(ev)) {
#ifdef XP_PC
char* str = PR_smprintf("Unable to create nspr log file '%s'\n", ev);
if (str) {
OutputDebugString(str);
PR_smprintf_free(str);
}
#else
fprintf(stderr, "Unable to create nspr log file '%s'\n", ev);
#endif
}
} else {
#ifdef _PR_USE_STDIO_FOR_LOGGING
logFile = stderr;
#else
logFile = _pr_stderr;
#endif
}
}
}
void _PR_LogCleanup(void)
{
PRLogModuleInfo *lm = logModules;
PR_LogFlush();
#ifdef _PR_USE_STDIO_FOR_LOGGING
if (logFile
&& logFile != stdout
&& logFile != stderr
#ifdef XP_PC
&& logFile != WIN32_DEBUG_FILE
#endif
) {
fclose(logFile);
}
#else
if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) {
PR_Close(logFile);
}
#endif
while (lm != NULL) {
PRLogModuleInfo *next = lm->next;
free((/*const*/ char *)lm->name);
PR_Free(lm);
lm = next;
}
logModules = NULL;
if (_pr_logLock) {
PR_DestroyLock(_pr_logLock);
_pr_logLock = NULL;
}
}
static void _PR_SetLogModuleLevel( PRLogModuleInfo *lm )
{
char *ev;
ev = PR_GetEnv("NSPR_LOG_MODULES");
if (ev && ev[0]) {
char module[64]; /* Security-Critical: If you change this
* size, you must also change the sscanf
* format string to be size-1.
*/
PRIntn evlen = strlen(ev), pos = 0;
while (pos < evlen) {
PRIntn level = 1, count = 0, delta = 0;
count = sscanf(&ev[pos], "%63[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-]%n:%d%n",
module, &delta, &level, &delta);
pos += delta;
if (count == 0) break;
/*
** If count == 2, then we got module and level. If count
** == 1, then level defaults to 1 (module enabled).
*/
if (lm != NULL)
{
if ((strcasecmp(module, "all") == 0)
|| (strcasecmp(module, lm->name) == 0))
{
lm->level = (PRLogModuleLevel)level;
}
}
count = sscanf(&ev[pos], " , %n", &delta);
pos += delta;
if (count == EOF) break;
}
}
} /* end _PR_SetLogModuleLevel() */
PR_IMPLEMENT(PRLogModuleInfo*) PR_NewLogModule(const char *name)
{
PRLogModuleInfo *lm;
if (!_pr_initialized) _PR_ImplicitInitialization();
lm = PR_NEWZAP(PRLogModuleInfo);
if (lm) {
lm->name = strdup(name);
lm->level = PR_LOG_NONE;
lm->next = logModules;
logModules = lm;
_PR_SetLogModuleLevel(lm);
}
return lm;
}
PR_IMPLEMENT(PRBool) PR_SetLogFile(const char *file)
{
#ifdef _PR_USE_STDIO_FOR_LOGGING
FILE *newLogFile;
#ifdef XP_PC
if ( strcmp( file, "WinDebug") == 0)
{
newLogFile = WIN32_DEBUG_FILE;
}
else
#endif
{
newLogFile = fopen(file, "w");
if (!newLogFile)
return PR_FALSE;
/* We do buffering ourselves. */
setvbuf(newLogFile, NULL, _IONBF, 0);
}
if (logFile
&& logFile != stdout
&& logFile != stderr
#ifdef XP_PC
&& logFile != WIN32_DEBUG_FILE
#endif
) {
fclose(logFile);
}
logFile = newLogFile;
return PR_TRUE;
#else
PRFileDesc *newLogFile;
newLogFile = PR_Open(file, PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, 0666);
if (newLogFile) {
if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) {
PR_Close(logFile);
}
logFile = newLogFile;
#if defined(XP_MAC)
SetLogFileTypeCreator(file);
#endif
}
return (PRBool) (newLogFile != 0);
#endif /* _PR_USE_STDIO_FOR_LOGGING */
}
PR_IMPLEMENT(void) PR_SetLogBuffering(PRIntn buffer_size)
{
PR_LogFlush();
if (logBuf)
PR_DELETE(logBuf);
if (buffer_size >= LINE_BUF_SIZE) {
logp = logBuf = (char*) PR_MALLOC(buffer_size);
logEndp = logp + buffer_size;
}
}
PR_IMPLEMENT(void) PR_LogPrint(const char *fmt, ...)
{
va_list ap;
char line[LINE_BUF_SIZE];
PRUint32 nb;
PRThread *me;
if (!_pr_initialized) _PR_ImplicitInitialization();
if (!logFile) {
return;
}
va_start(ap, fmt);
me = PR_GetCurrentThread();
nb = PR_snprintf(line, sizeof(line)-1, "%ld[%p]: ",
#if defined(_PR_DCETHREADS)
/* The problem is that for _PR_DCETHREADS, pthread_t is not a
* pointer, but a structure; so you can't easily print it...
*/
me ? &(me->id): 0L, me);
#elif defined(_PR_BTHREADS)
me, me);
#else
me ? me->id : 0L, me);
#endif
nb += PR_vsnprintf(line+nb, sizeof(line)-nb-1, fmt, ap);
if (nb && (line[nb-1] != '\n')) {
#ifndef XP_MAC
line[nb++] = '\n';
#else
line[nb++] = '\015';
#endif
line[nb] = '\0';
} else {
#ifdef XP_MAC
line[nb-1] = '\015';
#endif
}
va_end(ap);
_PR_LOCK_LOG();
if (logBuf == 0) {
_PUT_LOG(logFile, line, nb);
} else {
if (logp + nb > logEndp) {
_PUT_LOG(logFile, logBuf, logp - logBuf);
logp = logBuf;
}
memcpy(logp, line, nb);
logp += nb;
}
_PR_UNLOCK_LOG();
PR_LogFlush();
}
PR_IMPLEMENT(void) PR_LogFlush(void)
{
if (logBuf && logFile) {
_PR_LOCK_LOG();
if (logp > logBuf) {
_PUT_LOG(logFile, logBuf, logp - logBuf);
logp = logBuf;
}
_PR_UNLOCK_LOG();
}
}
PR_IMPLEMENT(void) PR_Abort(void)
{
PR_LogPrint("Aborting");
abort();
}
#if defined(XP_OS2)
/*
* Added definitions for DebugBreak() for 2 different OS/2 compilers.
* Doing the int3 on purpose for Visual Age so that a developer can
* step over the instruction if so desired. Not always possible if
* trapping due to exception handling IBM-AKR
*/
#if defined(XP_OS2_VACPP)
#include <builtin.h>
static void DebugBreak(void) { _interrupt(3); }
#elif defined(XP_OS2_EMX)
static void DebugBreak(void) { asm("int $3"); }
#else
static void DebugBreak(void) { }
#endif
#endif /* XP_OS2 */
PR_IMPLEMENT(void) PR_Assert(const char *s, const char *file, PRIntn ln)
{
PR_LogPrint("Assertion failure: %s, at %s:%d\n", s, file, ln);
#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln);
#endif
#ifdef XP_MAC
dprintf("Assertion failure: %s, at %s:%d\n", s, file, ln);
#endif
#if defined(WIN32) || defined(XP_OS2)
DebugBreak();
#endif
#ifndef XP_MAC
abort();
#endif
}
#ifdef XP_MAC
PR_IMPLEMENT(void) PR_Init_Log(void)
{
_PR_InitLog();
}
#endif
+517
View File
@@ -0,0 +1,517 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape Portable Runtime (NSPR).
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
* This file defines _PR_MapOptionName(). The purpose of putting
* _PR_MapOptionName() in a separate file is to work around a Winsock
* header file problem on Windows NT.
*
* On Windows NT, if we define _WIN32_WINNT to be 0x0400 (in order
* to use Service Pack 3 extensions), windows.h includes winsock2.h
* (instead of winsock.h), which doesn't define many socket options
* defined in winsock.h.
*
* We need the socket options defined in winsock.h. So this file
* includes winsock.h, with _WIN32_WINNT undefined.
*/
#if defined(WINNT) || defined(__MINGW32__)
#include <winsock.h>
#endif
/* MinGW doesn't define these in its winsock.h. */
#ifdef __MINGW32__
#ifndef IP_TTL
#define IP_TTL 7
#endif
#ifndef IP_TOS
#define IP_TOS 8
#endif
#endif
#include "primpl.h"
#if defined(NEXTSTEP)
/* NEXTSTEP is special: this must come before netinet/tcp.h. */
#include <netinet/in_systm.h> /* n_short, n_long, n_time */
#endif
#if defined(XP_UNIX) || defined(OS2) || (defined(XP_BEOS) && defined(BONE_VERSION))
#include <netinet/tcp.h> /* TCP_NODELAY, TCP_MAXSEG */
#endif
#ifndef _PR_PTHREADS
PRStatus PR_CALLBACK _PR_SocketGetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
{
PRStatus rv;
PRInt32 length;
PRInt32 level, name;
/*
* PR_SockOpt_Nonblocking is a special case that does not
* translate to a getsockopt() call
*/
if (PR_SockOpt_Nonblocking == data->option)
{
data->value.non_blocking = fd->secret->nonblocking;
return PR_SUCCESS;
}
rv = _PR_MapOptionName(data->option, &level, &name);
if (PR_SUCCESS == rv)
{
switch (data->option)
{
case PR_SockOpt_Linger:
{
#if !defined(XP_BEOS) || defined(BONE_VERSION)
struct linger linger;
length = sizeof(linger);
rv = _PR_MD_GETSOCKOPT(
fd, level, name, (char *) &linger, &length);
if (PR_SUCCESS == rv)
{
PR_ASSERT(sizeof(linger) == length);
data->value.linger.polarity =
(linger.l_onoff) ? PR_TRUE : PR_FALSE;
data->value.linger.linger =
PR_SecondsToInterval(linger.l_linger);
}
break;
#else
PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
return PR_FAILURE;
#endif
}
case PR_SockOpt_Reuseaddr:
case PR_SockOpt_Keepalive:
case PR_SockOpt_NoDelay:
case PR_SockOpt_Broadcast:
{
#ifdef WIN32 /* Winsock */
BOOL value;
#else
PRIntn value;
#endif
length = sizeof(value);
rv = _PR_MD_GETSOCKOPT(
fd, level, name, (char*)&value, &length);
if (PR_SUCCESS == rv)
data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
break;
}
case PR_SockOpt_McastLoopback:
{
#ifdef WIN32 /* Winsock */
BOOL bool;
#else
PRUint8 bool;
#endif
length = sizeof(bool);
rv = _PR_MD_GETSOCKOPT(
fd, level, name, (char*)&bool, &length);
if (PR_SUCCESS == rv)
data->value.mcast_loopback = (0 == bool) ? PR_FALSE : PR_TRUE;
break;
}
case PR_SockOpt_RecvBufferSize:
case PR_SockOpt_SendBufferSize:
case PR_SockOpt_MaxSegment:
{
PRIntn value;
length = sizeof(value);
rv = _PR_MD_GETSOCKOPT(
fd, level, name, (char*)&value, &length);
if (PR_SUCCESS == rv)
data->value.recv_buffer_size = value;
break;
}
case PR_SockOpt_IpTimeToLive:
case PR_SockOpt_IpTypeOfService:
{
/* These options should really be an int (or PRIntn). */
length = sizeof(PRUintn);
rv = _PR_MD_GETSOCKOPT(
fd, level, name, (char*)&data->value.ip_ttl, &length);
break;
}
case PR_SockOpt_McastTimeToLive:
{
#ifdef WIN32 /* Winsock */
int ttl;
#else
PRUint8 ttl;
#endif
length = sizeof(ttl);
rv = _PR_MD_GETSOCKOPT(
fd, level, name, (char*)&ttl, &length);
if (PR_SUCCESS == rv)
data->value.mcast_ttl = ttl;
break;
}
#ifdef IP_ADD_MEMBERSHIP
case PR_SockOpt_AddMember:
case PR_SockOpt_DropMember:
{
struct ip_mreq mreq;
length = sizeof(mreq);
rv = _PR_MD_GETSOCKOPT(
fd, level, name, (char*)&mreq, &length);
if (PR_SUCCESS == rv)
{
data->value.add_member.mcaddr.inet.ip =
mreq.imr_multiaddr.s_addr;
data->value.add_member.ifaddr.inet.ip =
mreq.imr_interface.s_addr;
}
break;
}
#endif /* IP_ADD_MEMBERSHIP */
case PR_SockOpt_McastInterface:
{
/* This option is a struct in_addr. */
length = sizeof(data->value.mcast_if.inet.ip);
rv = _PR_MD_GETSOCKOPT(
fd, level, name,
(char*)&data->value.mcast_if.inet.ip, &length);
break;
}
default:
PR_NOT_REACHED("Unknown socket option");
break;
}
}
return rv;
} /* _PR_SocketGetSocketOption */
PRStatus PR_CALLBACK _PR_SocketSetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
{
PRStatus rv;
PRInt32 level, name;
/*
* PR_SockOpt_Nonblocking is a special case that does not
* translate to a setsockopt call.
*/
if (PR_SockOpt_Nonblocking == data->option)
{
#ifdef WINNT
PR_ASSERT((fd->secret->md.io_model_committed == PR_FALSE)
|| (fd->secret->nonblocking == data->value.non_blocking));
if (fd->secret->md.io_model_committed
&& (fd->secret->nonblocking != data->value.non_blocking))
{
/*
* On NT, once we have associated a socket with the io
* completion port, we can't disassociate it. So we
* can't change the nonblocking option of the socket
* afterwards.
*/
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
return PR_FAILURE;
}
#endif
fd->secret->nonblocking = data->value.non_blocking;
return PR_SUCCESS;
}
rv = _PR_MapOptionName(data->option, &level, &name);
if (PR_SUCCESS == rv)
{
switch (data->option)
{
case PR_SockOpt_Linger:
{
#if !defined(XP_BEOS) || defined(BONE_VERSION)
struct linger linger;
linger.l_onoff = data->value.linger.polarity;
linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
rv = _PR_MD_SETSOCKOPT(
fd, level, name, (char*)&linger, sizeof(linger));
break;
#else
PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
return PR_FAILURE;
#endif
}
case PR_SockOpt_Reuseaddr:
case PR_SockOpt_Keepalive:
case PR_SockOpt_NoDelay:
case PR_SockOpt_Broadcast:
{
#ifdef WIN32 /* Winsock */
BOOL value;
#else
PRIntn value;
#endif
value = (data->value.reuse_addr) ? 1 : 0;
rv = _PR_MD_SETSOCKOPT(
fd, level, name, (char*)&value, sizeof(value));
break;
}
case PR_SockOpt_McastLoopback:
{
#ifdef WIN32 /* Winsock */
BOOL bool;
#else
PRUint8 bool;
#endif
bool = data->value.mcast_loopback ? 1 : 0;
rv = _PR_MD_SETSOCKOPT(
fd, level, name, (char*)&bool, sizeof(bool));
break;
}
case PR_SockOpt_RecvBufferSize:
case PR_SockOpt_SendBufferSize:
case PR_SockOpt_MaxSegment:
{
PRIntn value = data->value.recv_buffer_size;
rv = _PR_MD_SETSOCKOPT(
fd, level, name, (char*)&value, sizeof(value));
break;
}
case PR_SockOpt_IpTimeToLive:
case PR_SockOpt_IpTypeOfService:
{
/* These options should really be an int (or PRIntn). */
rv = _PR_MD_SETSOCKOPT(
fd, level, name, (char*)&data->value.ip_ttl, sizeof(PRUintn));
break;
}
case PR_SockOpt_McastTimeToLive:
{
#ifdef WIN32 /* Winsock */
int ttl;
#else
PRUint8 ttl;
#endif
ttl = data->value.mcast_ttl;
rv = _PR_MD_SETSOCKOPT(
fd, level, name, (char*)&ttl, sizeof(ttl));
break;
}
#ifdef IP_ADD_MEMBERSHIP
case PR_SockOpt_AddMember:
case PR_SockOpt_DropMember:
{
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr =
data->value.add_member.mcaddr.inet.ip;
mreq.imr_interface.s_addr =
data->value.add_member.ifaddr.inet.ip;
rv = _PR_MD_SETSOCKOPT(
fd, level, name, (char*)&mreq, sizeof(mreq));
break;
}
#endif /* IP_ADD_MEMBERSHIP */
case PR_SockOpt_McastInterface:
{
/* This option is a struct in_addr. */
rv = _PR_MD_SETSOCKOPT(
fd, level, name, (char*)&data->value.mcast_if.inet.ip,
sizeof(data->value.mcast_if.inet.ip));
break;
}
default:
PR_NOT_REACHED("Unknown socket option");
break;
}
}
return rv;
} /* _PR_SocketSetSocketOption */
#endif /* ! _PR_PTHREADS */
/*
*********************************************************************
*********************************************************************
**
** Make sure that the following is at the end of this file,
** because we will be playing with macro redefines.
**
*********************************************************************
*********************************************************************
*/
#if defined(VMS)
/*
** Sad but true. The DEC C header files define the following socket options
** differently to what UCX is expecting. The values that UCX expects are
** defined in SYS$LIBRARY:UCX$INETDEF.H. We redefine them here to the values
** that UCX expects. Note that UCX V4.x will only accept these values while
** UCX V5.x will accept either. So in theory this hack can be removed once
** UCX V5 is the minimum.
*/
#undef IP_MULTICAST_IF
#undef IP_MULTICAST_TTL
#undef IP_MULTICAST_LOOP
#undef IP_ADD_MEMBERSHIP
#undef IP_DROP_MEMBERSHIP
#include <ucx$inetdef.h>
#define IP_MULTICAST_IF UCX$C_IP_MULTICAST_IF
#define IP_MULTICAST_TTL UCX$C_IP_MULTICAST_TTL
#define IP_MULTICAST_LOOP UCX$C_IP_MULTICAST_LOOP
#define IP_ADD_MEMBERSHIP UCX$C_IP_ADD_MEMBERSHIP
#define IP_DROP_MEMBERSHIP UCX$C_IP_DROP_MEMBERSHIP
#endif
/*
* Not every platform has all the socket options we want to
* support. Some older operating systems such as SunOS 4.1.3
* don't have the IP multicast socket options. Win32 doesn't
* have TCP_MAXSEG.
*
* To deal with this problem, we define the missing socket
* options as _PR_NO_SUCH_SOCKOPT. _PR_MapOptionName() fails with
* PR_OPERATION_NOT_SUPPORTED_ERROR if a socket option not
* available on the platform is requested.
*/
/*
* Sanity check. SO_LINGER and TCP_NODELAY should be available
* on all platforms. Just to make sure we have included the
* appropriate header files. Then any undefined socket options
* are really missing.
*/
#if !defined(SO_LINGER)
#error "SO_LINGER is not defined"
#endif
/*
* Some platforms, such as NCR 2.03, don't have TCP_NODELAY defined
* in <netinet/tcp.h>
*/
#if !defined(NCR)
#if !defined(TCP_NODELAY)
#error "TCP_NODELAY is not defined"
#endif
#endif
/*
* Make sure the value of _PR_NO_SUCH_SOCKOPT is not
* a valid socket option.
*/
#define _PR_NO_SUCH_SOCKOPT -1
#ifndef SO_KEEPALIVE
#define SO_KEEPALIVE _PR_NO_SUCH_SOCKOPT
#endif
#ifndef SO_SNDBUF
#define SO_SNDBUF _PR_NO_SUCH_SOCKOPT
#endif
#ifndef SO_RCVBUF
#define SO_RCVBUF _PR_NO_SUCH_SOCKOPT
#endif
#ifndef IP_MULTICAST_IF /* set/get IP multicast interface */
#define IP_MULTICAST_IF _PR_NO_SUCH_SOCKOPT
#endif
#ifndef IP_MULTICAST_TTL /* set/get IP multicast timetolive */
#define IP_MULTICAST_TTL _PR_NO_SUCH_SOCKOPT
#endif
#ifndef IP_MULTICAST_LOOP /* set/get IP multicast loopback */
#define IP_MULTICAST_LOOP _PR_NO_SUCH_SOCKOPT
#endif
#ifndef IP_ADD_MEMBERSHIP /* add an IP group membership */
#define IP_ADD_MEMBERSHIP _PR_NO_SUCH_SOCKOPT
#endif
#ifndef IP_DROP_MEMBERSHIP /* drop an IP group membership */
#define IP_DROP_MEMBERSHIP _PR_NO_SUCH_SOCKOPT
#endif
#ifndef IP_TTL /* set/get IP Time To Live */
#define IP_TTL _PR_NO_SUCH_SOCKOPT
#endif
#ifndef IP_TOS /* set/get IP Type Of Service */
#define IP_TOS _PR_NO_SUCH_SOCKOPT
#endif
#ifndef TCP_NODELAY /* don't delay to coalesce data */
#define TCP_NODELAY _PR_NO_SUCH_SOCKOPT
#endif
#ifndef TCP_MAXSEG /* maxumum segment size for tcp */
#define TCP_MAXSEG _PR_NO_SUCH_SOCKOPT
#endif
#ifndef SO_BROADCAST /* enable broadcast on udp sockets */
#define SO_BROADCAST _PR_NO_SUCH_SOCKOPT
#endif
PRStatus _PR_MapOptionName(
PRSockOption optname, PRInt32 *level, PRInt32 *name)
{
static PRInt32 socketOptions[PR_SockOpt_Last] =
{
0, SO_LINGER, SO_REUSEADDR, SO_KEEPALIVE, SO_RCVBUF, SO_SNDBUF,
IP_TTL, IP_TOS, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP,
IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_MULTICAST_LOOP,
TCP_NODELAY, TCP_MAXSEG, SO_BROADCAST
};
static PRInt32 socketLevels[PR_SockOpt_Last] =
{
0, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET,
IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
IPPROTO_TCP, IPPROTO_TCP, SOL_SOCKET
};
if ((optname < PR_SockOpt_Linger)
|| (optname >= PR_SockOpt_Last))
{
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
return PR_FAILURE;
}
if (socketOptions[optname] == _PR_NO_SUCH_SOCKOPT)
{
PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
return PR_FAILURE;
}
*name = socketOptions[optname];
*level = socketLevels[optname];
return PR_SUCCESS;
} /* _PR_MapOptionName */
+93
View File
@@ -0,0 +1,93 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape Portable Runtime (NSPR).
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
*********************************************************************
*
* Memory-mapped files
*
*********************************************************************
*/
#include "primpl.h"
PR_IMPLEMENT(PRFileMap *) PR_CreateFileMap(
PRFileDesc *fd,
PRInt64 size,
PRFileMapProtect prot)
{
PRFileMap *fmap;
PR_ASSERT(prot == PR_PROT_READONLY || prot == PR_PROT_READWRITE
|| prot == PR_PROT_WRITECOPY);
fmap = PR_NEWZAP(PRFileMap);
if (NULL == fmap) {
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
return NULL;
}
fmap->fd = fd;
fmap->prot = prot;
if (_PR_MD_CREATE_FILE_MAP(fmap, size) == PR_SUCCESS) {
return fmap;
} else {
PR_DELETE(fmap);
return NULL;
}
}
PR_IMPLEMENT(PRInt32) PR_GetMemMapAlignment(void)
{
return _PR_MD_GET_MEM_MAP_ALIGNMENT();
}
PR_IMPLEMENT(void *) PR_MemMap(
PRFileMap *fmap,
PROffset64 offset,
PRUint32 len)
{
return _PR_MD_MEM_MAP(fmap, offset, len);
}
PR_IMPLEMENT(PRStatus) PR_MemUnmap(void *addr, PRUint32 len)
{
return _PR_MD_MEM_UNMAP(addr, len);
}
PR_IMPLEMENT(PRStatus) PR_CloseFileMap(PRFileMap *fmap)
{
return _PR_MD_CLOSE_FILE_MAP(fmap);
}
File diff suppressed because it is too large. Load diff
+530
View File
@@ -0,0 +1,530 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape Portable Runtime (NSPR).
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
*********************************************************************
*
* Pollable events
*
* Pollable events are implemented using layered I/O. The only
* I/O methods that are implemented for pollable events are poll
* and close. No other methods can be invoked on a pollable
* event.
*
* A pipe or socket pair is created and the pollable event layer
* is pushed onto the read end. A pointer to the write end is
* saved in the PRFilePrivate structure of the pollable event.
*
*********************************************************************
*/
#include "prinit.h"
#include "prio.h"
#include "prmem.h"
#include "prerror.h"
#include "prlog.h"
#ifdef VMS
/*
* On OpenVMS we use an event flag instead of a pipe or a socket since
* event flags are much more efficient on OpenVMS.
*/
#include "pprio.h"
#include <lib$routines.h>
#include <starlet.h>
#include <stsdef.h>
PR_IMPLEMENT(PRFileDesc *) PR_NewPollableEvent(void)
{
unsigned int status;
int flag = -1;
PRFileDesc *event;
/*
** Allocate an event flag and clear it.
*/
status = lib$get_ef(&flag);
if ((!$VMS_STATUS_SUCCESS(status)) || (flag == -1)) {
PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, status);
return NULL;
}
sys$clref(flag);
/*
** Give NSPR the event flag's negative value. We do this because our
** select interprets a negative fd as an event flag rather than a
** regular file fd.
*/
event = PR_CreateSocketPollFd(-flag);
if (NULL == event) {
lib$free_ef(&flag);
return NULL;
}
return event;
}
PR_IMPLEMENT(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event)
{
int flag = -PR_FileDesc2NativeHandle(event);
PR_DestroySocketPollFd(event);
lib$free_ef(&flag);
return PR_SUCCESS;
}
PR_IMPLEMENT(PRStatus) PR_SetPollableEvent(PRFileDesc *event)
{
/*
** Just set the event flag.
*/
unsigned int status;
status = sys$setef(-PR_FileDesc2NativeHandle(event));
if (!$VMS_STATUS_SUCCESS(status)) {
PR_SetError(PR_INVALID_ARGUMENT_ERROR, status);
return PR_FAILURE;
}
return PR_SUCCESS;
}
PR_IMPLEMENT(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event)
{
/*
** Just clear the event flag.
*/
unsigned int status;
status = sys$clref(-PR_FileDesc2NativeHandle(event));
if (!$VMS_STATUS_SUCCESS(status)) {
PR_SetError(PR_INVALID_ARGUMENT_ERROR, status);
return PR_FAILURE;
}
return PR_SUCCESS;
}
#elif defined (XP_MAC)
#include "primpl.h"
/*
* On Mac, local sockets cannot be used, because the networking stack
* closes them when the machine goes to sleep. Instead, we'll use a simple
* flag.
*/
/*
* PRFilePrivate structure for the NSPR pollable events layer
*/
typedef struct PRPollableDesc {
PRBool gotEvent;
PRThread *pollingThread;
} PRPollableDesc;
static PRStatus PR_CALLBACK _pr_MacPolEvtClose(PRFileDesc *fd);
static PRInt16 PR_CALLBACK _pr_MacPolEvtPoll(
PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags);
static PRIOMethods _pr_mac_polevt_methods = {
PR_DESC_LAYERED,
_pr_MacPolEvtClose,
(PRReadFN)_PR_InvalidInt,
(PRWriteFN)_PR_InvalidInt,
(PRAvailableFN)_PR_InvalidInt,
(PRAvailable64FN)_PR_InvalidInt64,
(PRFsyncFN)_PR_InvalidStatus,
(PRSeekFN)_PR_InvalidInt,
(PRSeek64FN)_PR_InvalidInt64,
(PRFileInfoFN)_PR_InvalidStatus,
(PRFileInfo64FN)_PR_InvalidStatus,
(PRWritevFN)_PR_InvalidInt,
(PRConnectFN)_PR_InvalidStatus,
(PRAcceptFN)_PR_InvalidDesc,
(PRBindFN)_PR_InvalidStatus,
(PRListenFN)_PR_InvalidStatus,
(PRShutdownFN)_PR_InvalidStatus,
(PRRecvFN)_PR_InvalidInt,
(PRSendFN)_PR_InvalidInt,
(PRRecvfromFN)_PR_InvalidInt,
(PRSendtoFN)_PR_InvalidInt,
_pr_MacPolEvtPoll,
(PRAcceptreadFN)_PR_InvalidInt,
(PRTransmitfileFN)_PR_InvalidInt,
(PRGetsocknameFN)_PR_InvalidStatus,
(PRGetpeernameFN)_PR_InvalidStatus,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt,
(PRGetsocketoptionFN)_PR_InvalidStatus,
(PRSetsocketoptionFN)_PR_InvalidStatus,
(PRSendfileFN)_PR_InvalidInt,
(PRConnectcontinueFN)_PR_InvalidStatus,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt
};
static PRDescIdentity _pr_mac_polevt_id;
static PRCallOnceType _pr_mac_polevt_once_control;
static PRStatus PR_CALLBACK _pr_MacPolEvtInit(void);
static PRInt16 PR_CALLBACK _pr_MacPolEvtPoll(
PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
{
PRPollableDesc *pollDesc = (PRPollableDesc *)fd->secret;
PR_ASSERT(pollDesc);
// set the current thread so that we can wake up the poll thread
pollDesc->pollingThread = PR_GetCurrentThread();
if ((in_flags & PR_POLL_READ) && pollDesc->gotEvent)
*out_flags = PR_POLL_READ;
else
*out_flags = 0;
return pollDesc->gotEvent ? 1 : 0;
}
static PRStatus PR_CALLBACK _pr_MacPolEvtInit(void)
{
_pr_mac_polevt_id = PR_GetUniqueIdentity("NSPR pollable events");
if (PR_INVALID_IO_LAYER == _pr_mac_polevt_id) {
return PR_FAILURE;
}
return PR_SUCCESS;
}
static PRStatus PR_CALLBACK _pr_MacPolEvtClose(PRFileDesc *fd)
{
PRPollableDesc *pollDesc = (PRPollableDesc *)fd->secret;
PR_ASSERT(NULL == fd->higher && NULL == fd->lower);
PR_ASSERT(pollDesc);
PR_DELETE(pollDesc);
fd->dtor(fd);
return PR_SUCCESS;
}
PR_IMPLEMENT(PRFileDesc *) PR_NewPollableEvent(void)
{
PRFileDesc *event;
PRPollableDesc *pollDesc;
if (PR_CallOnce(&_pr_mac_polevt_once_control, _pr_MacPolEvtInit) == PR_FAILURE) {
return NULL;
}
event = PR_CreateIOLayerStub(_pr_mac_polevt_id, &_pr_mac_polevt_methods);
if (NULL == event) {
return NULL;
}
/*
** Allocate an event flag and clear it.
*/
pollDesc = PR_NEW(PRPollableDesc);
if (!pollDesc) {
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
goto errorExit;
}
pollDesc->gotEvent = PR_FALSE;
pollDesc->pollingThread = NULL;
event->secret = (PRFilePrivate*)pollDesc;
return event;
errorExit:
if (event) {
PR_DELETE(event->secret);
event->dtor(event);
}
return NULL;
}
PR_IMPLEMENT(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event)
{
return PR_Close(event);
}
/* from macsockotpt.c. I wish there was a cleaner way */
extern void WakeUpNotifiedThread(PRThread *thread, OTResult result);
PR_IMPLEMENT(PRStatus) PR_SetPollableEvent(PRFileDesc *event)
{
PRPollableDesc *pollDesc = (PRPollableDesc *)event->secret;
PR_ASSERT(pollDesc);
PR_ASSERT(pollDesc->pollingThread->state != _PR_DEAD_STATE);
if (pollDesc->pollingThread->state == _PR_DEAD_STATE)
return PR_FAILURE;
pollDesc->gotEvent = PR_TRUE;
if (pollDesc->pollingThread)
WakeUpNotifiedThread(pollDesc->pollingThread, noErr);
return PR_SUCCESS;
}
PR_IMPLEMENT(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event)
{
PRPollableDesc *pollDesc = (PRPollableDesc *)event->secret;
PRStatus status;
PR_ASSERT(pollDesc);
/*
FIXME: Danger Will Robinson!
The current implementation of PR_WaitForPollableEvent is somewhat
bogus; it makes the assumption that, in Mozilla, this will only
ever be called when PR_Poll has returned, telling us that an
event has been set.
*/
PR_ASSERT(pollDesc->gotEvent);
status = (pollDesc->gotEvent) ? PR_SUCCESS : PR_FAILURE;
pollDesc->gotEvent = PR_FALSE;
return status;
}
#else /* VMS */
/*
* These internal functions are declared in primpl.h,
* but we can't include primpl.h because the definition
* of struct PRFilePrivate in this file (for the pollable
* event layer) will conflict with the definition of
* struct PRFilePrivate in primpl.h (for the NSPR layer).
*/
extern PRIntn _PR_InvalidInt(void);
extern PRInt64 _PR_InvalidInt64(void);
extern PRStatus _PR_InvalidStatus(void);
extern PRFileDesc *_PR_InvalidDesc(void);
/*
* PRFilePrivate structure for the NSPR pollable events layer
*/
struct PRFilePrivate {
PRFileDesc *writeEnd; /* the write end of the pipe/socketpair */
};
static PRStatus PR_CALLBACK _pr_PolEvtClose(PRFileDesc *fd);
static PRInt16 PR_CALLBACK _pr_PolEvtPoll(
PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags);
static PRIOMethods _pr_polevt_methods = {
PR_DESC_LAYERED,
_pr_PolEvtClose,
(PRReadFN)_PR_InvalidInt,
(PRWriteFN)_PR_InvalidInt,
(PRAvailableFN)_PR_InvalidInt,
(PRAvailable64FN)_PR_InvalidInt64,
(PRFsyncFN)_PR_InvalidStatus,
(PRSeekFN)_PR_InvalidInt,
(PRSeek64FN)_PR_InvalidInt64,
(PRFileInfoFN)_PR_InvalidStatus,
(PRFileInfo64FN)_PR_InvalidStatus,
(PRWritevFN)_PR_InvalidInt,
(PRConnectFN)_PR_InvalidStatus,
(PRAcceptFN)_PR_InvalidDesc,
(PRBindFN)_PR_InvalidStatus,
(PRListenFN)_PR_InvalidStatus,
(PRShutdownFN)_PR_InvalidStatus,
(PRRecvFN)_PR_InvalidInt,
(PRSendFN)_PR_InvalidInt,
(PRRecvfromFN)_PR_InvalidInt,
(PRSendtoFN)_PR_InvalidInt,
_pr_PolEvtPoll,
(PRAcceptreadFN)_PR_InvalidInt,
(PRTransmitfileFN)_PR_InvalidInt,
(PRGetsocknameFN)_PR_InvalidStatus,
(PRGetpeernameFN)_PR_InvalidStatus,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt,
(PRGetsocketoptionFN)_PR_InvalidStatus,
(PRSetsocketoptionFN)_PR_InvalidStatus,
(PRSendfileFN)_PR_InvalidInt,
(PRConnectcontinueFN)_PR_InvalidStatus,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt,
(PRReservedFN)_PR_InvalidInt
};
static PRDescIdentity _pr_polevt_id;
static PRCallOnceType _pr_polevt_once_control;
static PRStatus PR_CALLBACK _pr_PolEvtInit(void);
static PRInt16 PR_CALLBACK _pr_PolEvtPoll(
PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
{
return (fd->lower->methods->poll)(fd->lower, in_flags, out_flags);
}
static PRStatus PR_CALLBACK _pr_PolEvtInit(void)
{
_pr_polevt_id = PR_GetUniqueIdentity("NSPR pollable events");
if (PR_INVALID_IO_LAYER == _pr_polevt_id) {
return PR_FAILURE;
}
return PR_SUCCESS;
}
#if !defined(XP_UNIX)
#define USE_TCP_SOCKETPAIR
#endif
PR_IMPLEMENT(PRFileDesc *) PR_NewPollableEvent(void)
{
PRFileDesc *event;
PRFileDesc *fd[2]; /* fd[0] is the read end; fd[1] is the write end */
#ifdef USE_TCP_SOCKETPAIR
PRSocketOptionData socket_opt;
PRStatus rv;
#endif
fd[0] = fd[1] = NULL;
if (PR_CallOnce(&_pr_polevt_once_control, _pr_PolEvtInit) == PR_FAILURE) {
return NULL;
}
event = PR_CreateIOLayerStub(_pr_polevt_id, &_pr_polevt_methods);
if (NULL == event) {
goto errorExit;
}
event->secret = PR_NEW(PRFilePrivate);
if (event->secret == NULL) {
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
goto errorExit;
}
#ifndef USE_TCP_SOCKETPAIR
if (PR_CreatePipe(&fd[0], &fd[1]) == PR_FAILURE) {
fd[0] = fd[1] = NULL;
goto errorExit;
}
#else
if (PR_NewTCPSocketPair(fd) == PR_FAILURE) {
fd[0] = fd[1] = NULL;
goto errorExit;
}
/*
* set the TCP_NODELAY option to reduce notification latency
*/
socket_opt.option = PR_SockOpt_NoDelay;
socket_opt.value.no_delay = PR_TRUE;
rv = PR_SetSocketOption(fd[1], &socket_opt);
PR_ASSERT(PR_SUCCESS == rv);
#endif
event->secret->writeEnd = fd[1];
if (PR_PushIOLayer(fd[0], PR_TOP_IO_LAYER, event) == PR_FAILURE) {
goto errorExit;
}
return fd[0];
errorExit:
if (fd[0]) {
PR_Close(fd[0]);
PR_Close(fd[1]);
}
if (event) {
PR_DELETE(event->secret);
event->dtor(event);
}
return NULL;
}
static PRStatus PR_CALLBACK _pr_PolEvtClose(PRFileDesc *fd)
{
PRFileDesc *event;
event = PR_PopIOLayer(fd, PR_TOP_IO_LAYER);
PR_ASSERT(NULL == event->higher && NULL == event->lower);
PR_Close(fd);
PR_Close(event->secret->writeEnd);
PR_DELETE(event->secret);
event->dtor(event);
return PR_SUCCESS;
}
PR_IMPLEMENT(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event)
{
return PR_Close(event);
}
static const char magicChar = '\x38';
PR_IMPLEMENT(PRStatus) PR_SetPollableEvent(PRFileDesc *event)
{
if (PR_Write(event->secret->writeEnd, &magicChar, 1) != 1) {
return PR_FAILURE;
}
return PR_SUCCESS;
}
PR_IMPLEMENT(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event)
{
char buf[1024];
PRInt32 nBytes;
#ifdef DEBUG
PRIntn i;
#endif
nBytes = PR_Read(event->lower, buf, sizeof(buf));
if (nBytes == -1) {
return PR_FAILURE;
}
#ifdef DEBUG
/*
* Make sure people do not write to the pollable event fd
* directly.
*/
for (i = 0; i < nBytes; i++) {
PR_ASSERT(buf[i] == magicChar);
}
#endif
return PR_SUCCESS;
}
#endif /* VMS */
File diff suppressed because it is too large. Load diff
+669
View File
@@ -0,0 +1,669 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape Portable Runtime (NSPR).
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
* Scan functions for NSPR types
*
* Author: Wan-Teh Chang
*
* Acknowledgment: The implementation is inspired by the source code
* in P.J. Plauger's "The Standard C Library," Prentice-Hall, 1992.
*/
#include <limits.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#ifdef SUNOS4
#include "md/sunos4.h" /* for strtoul */
#endif
#include "prprf.h"
#include "prdtoa.h"
#include "prlog.h"
#include "prerror.h"
/*
* A function that reads a character from 'stream'.
* Returns the character read, or EOF if end of stream is reached.
*/
typedef int (*_PRGetCharFN)(void *stream);
/*
* A function that pushes the character 'ch' back to 'stream'.
*/
typedef void (*_PRUngetCharFN)(void *stream, int ch);
/*
* The size specifier for the integer and floating point number
* conversions in format control strings.
*/
typedef enum {
_PR_size_none, /* No size specifier is given */
_PR_size_h, /* The 'h' specifier, suggesting "short" */
_PR_size_l, /* The 'l' specifier, suggesting "long" */
_PR_size_L, /* The 'L' specifier, meaning a 'long double' */
_PR_size_ll /* The 'll' specifier, suggesting "long long" */
} _PRSizeSpec;
/*
* The collection of data that is passed between the scan function
* and its subordinate functions. The fields of this structure
* serve as the input or output arguments for these functions.
*/
typedef struct {
_PRGetCharFN get; /* get a character from input stream */
_PRUngetCharFN unget; /* unget (push back) a character */
void *stream; /* argument for get and unget */
va_list ap; /* the variable argument list */
int nChar; /* number of characters read from 'stream' */
PRBool assign; /* assign, or suppress assignment? */
int width; /* field width */
_PRSizeSpec sizeSpec; /* 'h', 'l', 'L', or 'll' */
PRBool converted; /* is the value actually converted? */
} ScanfState;
#define GET(state) ((state)->nChar++, (state)->get((state)->stream))
#define UNGET(state, ch) \
((state)->nChar--, (state)->unget((state)->stream, ch))
/*
* The following two macros, GET_IF_WITHIN_WIDTH and WITHIN_WIDTH,
* are always used together.
*
* GET_IF_WITHIN_WIDTH calls the GET macro and assigns its return
* value to 'ch' only if we have not exceeded the field width of
* 'state'. Therefore, after GET_IF_WITHIN_WIDTH, the value of
* 'ch' is valid only if the macro WITHIN_WIDTH evaluates to true.
*/
#define GET_IF_WITHIN_WIDTH(state, ch) \
if (--(state)->width >= 0) { \
(ch) = GET(state); \
}
#define WITHIN_WIDTH(state) ((state)->width >= 0)
/*
* _pr_strtoull:
* Convert a string to an unsigned 64-bit integer. The string
* 'str' is assumed to be a representation of the integer in
* base 'base'.
*
* Warning:
* - Only handle base 8, 10, and 16.
* - No overflow checking.
*/
static PRUint64
_pr_strtoull(const char *str, char **endptr, int base)
{
static const int BASE_MAX = 16;
static const char digits[] = "0123456789abcdef";
char *digitPtr;
PRUint64 x; /* return value */
PRInt64 base64;
const char *cPtr;
PRBool negative;
const char *digitStart;
PR_ASSERT(base == 0 || base == 8 || base == 10 || base == 16);
if (base < 0 || base == 1 || base > BASE_MAX) {
if (endptr) {
*endptr = (char *) str;
return LL_ZERO;
}
}
cPtr = str;
while (isspace(*cPtr)) {
++cPtr;
}
negative = PR_FALSE;
if (*cPtr == '-') {
negative = PR_TRUE;
cPtr++;
} else if (*cPtr == '+') {
cPtr++;
}
if (base == 16) {
if (*cPtr == '0' && (cPtr[1] == 'x' || cPtr[1] == 'X')) {
cPtr += 2;
}
} else if (base == 0) {
if (*cPtr != '0') {
base = 10;
} else if (cPtr[1] == 'x' || cPtr[1] == 'X') {
base = 16;
cPtr += 2;
} else {
base = 8;
}
}
PR_ASSERT(base != 0);
LL_I2L(base64, base);
digitStart = cPtr;
/* Skip leading zeros */
while (*cPtr == '0') {
cPtr++;
}
LL_I2L(x, 0);
while ((digitPtr = (char*)memchr(digits, tolower(*cPtr), base)) != NULL) {
PRUint64 d;
LL_I2L(d, (digitPtr - digits));
LL_MUL(x, x, base64);
LL_ADD(x, x, d);
cPtr++;
}
if (cPtr == digitStart) {
if (endptr) {
*endptr = (char *) str;
}
return LL_ZERO;
}
if (negative) {
#ifdef HAVE_LONG_LONG
/* The cast to a signed type is to avoid a compiler warning */
x = -(PRInt64)x;
#else
LL_NEG(x, x);
#endif
}
if (endptr) {
*endptr = (char *) cPtr;
}
return x;
}
/*
* The maximum field width (in number of characters) that is enough
* (may be more than necessary) to represent a 64-bit integer or
* floating point number.
*/
#define FMAX 31
#define DECIMAL_POINT '.'
static PRStatus
GetInt(ScanfState *state, int code)
{
char buf[FMAX + 1], *p;
int ch;
static const char digits[] = "0123456789abcdefABCDEF";
PRBool seenDigit = PR_FALSE;
int base;
int dlen;
switch (code) {
case 'd': case 'u':
base = 10;
break;
case 'i':
base = 0;
break;
case 'x': case 'X': case 'p':
base = 16;
break;
case 'o':
base = 8;
break;
default:
return PR_FAILURE;
}
if (state->width == 0 || state->width > FMAX) {
state->width = FMAX;
}
p = buf;
GET_IF_WITHIN_WIDTH(state, ch);
if (WITHIN_WIDTH(state) && (ch == '+' || ch == '-')) {
*p++ = ch;
GET_IF_WITHIN_WIDTH(state, ch);
}
if (WITHIN_WIDTH(state) && ch == '0') {
seenDigit = PR_TRUE;
*p++ = ch;
GET_IF_WITHIN_WIDTH(state, ch);
if (WITHIN_WIDTH(state)
&& (ch == 'x' || ch == 'X')
&& (base == 0 || base == 16)) {
base = 16;
*p++ = ch;
GET_IF_WITHIN_WIDTH(state, ch);
} else if (base == 0) {
base = 8;
}
}
if (base == 0 || base == 10) {
dlen = 10;
} else if (base == 8) {
dlen = 8;
} else {
PR_ASSERT(base == 16);
dlen = 16 + 6; /* 16 digits, plus 6 in uppercase */
}
while (WITHIN_WIDTH(state) && memchr(digits, ch, dlen)) {
*p++ = ch;
GET_IF_WITHIN_WIDTH(state, ch);
seenDigit = PR_TRUE;
}
if (WITHIN_WIDTH(state)) {
UNGET(state, ch);
}
if (!seenDigit) {
return PR_FAILURE;
}
*p = '\0';
if (state->assign) {
if (code == 'd' || code == 'i') {
if (state->sizeSpec == _PR_size_ll) {
PRInt64 llval = _pr_strtoull(buf, NULL, base);
*va_arg(state->ap, PRInt64 *) = llval;
} else {
long lval = strtol(buf, NULL, base);
if (state->sizeSpec == _PR_size_none) {
*va_arg(state->ap, PRIntn *) = lval;
} else if (state->sizeSpec == _PR_size_h) {
*va_arg(state->ap, PRInt16 *) = (PRInt16)lval;
} else if (state->sizeSpec == _PR_size_l) {
*va_arg(state->ap, PRInt32 *) = lval;
} else {
return PR_FAILURE;
}
}
} else {
if (state->sizeSpec == _PR_size_ll) {
PRUint64 llval = _pr_strtoull(buf, NULL, base);
*va_arg(state->ap, PRUint64 *) = llval;
} else {
unsigned long lval = strtoul(buf, NULL, base);
if (state->sizeSpec == _PR_size_none) {
*va_arg(state->ap, PRUintn *) = lval;
} else if (state->sizeSpec == _PR_size_h) {
*va_arg(state->ap, PRUint16 *) = (PRUint16)lval;
} else if (state->sizeSpec == _PR_size_l) {
*va_arg(state->ap, PRUint32 *) = lval;
} else {
return PR_FAILURE;
}
}
}
state->converted = PR_TRUE;
}
return PR_SUCCESS;
}
static PRStatus
GetFloat(ScanfState *state)
{
char buf[FMAX + 1], *p;
int ch;
PRBool seenDigit = PR_FALSE;
if (state->width == 0 || state->width > FMAX) {
state->width = FMAX;
}
p = buf;
GET_IF_WITHIN_WIDTH(state, ch);
if (WITHIN_WIDTH(state) && (ch == '+' || ch == '-')) {
*p++ = ch;
GET_IF_WITHIN_WIDTH(state, ch);
}
while (WITHIN_WIDTH(state) && isdigit(ch)) {
*p++ = ch;
GET_IF_WITHIN_WIDTH(state, ch);
seenDigit = PR_TRUE;
}
if (WITHIN_WIDTH(state) && ch == DECIMAL_POINT) {
*p++ = ch;
GET_IF_WITHIN_WIDTH(state, ch);
while (WITHIN_WIDTH(state) && isdigit(ch)) {
*p++ = ch;
GET_IF_WITHIN_WIDTH(state, ch);
seenDigit = PR_TRUE;
}
}
/*
* This is not robust. For example, "1.2e+" would confuse
* the code below to read 'e' and '+', only to realize that
* it should have stopped at "1.2". But we can't push back
* more than one character, so there is nothing I can do.
*/
/* Parse exponent */
if (WITHIN_WIDTH(state) && (ch == 'e' || ch == 'E') && seenDigit) {
*p++ = ch;
GET_IF_WITHIN_WIDTH(state, ch);
if (WITHIN_WIDTH(state) && (ch == '+' || ch == '-')) {
*p++ = ch;
GET_IF_WITHIN_WIDTH(state, ch);
}
while (WITHIN_WIDTH(state) && isdigit(ch)) {
*p++ = ch;
GET_IF_WITHIN_WIDTH(state, ch);
}
}
if (WITHIN_WIDTH(state)) {
UNGET(state, ch);
}
if (!seenDigit) {
return PR_FAILURE;
}
*p = '\0';
if (state->assign) {
PRFloat64 dval = PR_strtod(buf, NULL);
state->converted = PR_TRUE;
if (state->sizeSpec == _PR_size_l) {
*va_arg(state->ap, PRFloat64 *) = dval;
} else if (state->sizeSpec == _PR_size_L) {
#if defined(OSF1) || defined(IRIX)
*va_arg(state->ap, double *) = dval;
#else
*va_arg(state->ap, long double *) = dval;
#endif
} else {
*va_arg(state->ap, float *) = (float) dval;
}
}
return PR_SUCCESS;
}
/*
* Convert, and return the end of the conversion spec.
* Return NULL on error.
*/
static const char *
Convert(ScanfState *state, const char *fmt)
{
const char *cPtr;
int ch;
char *cArg = NULL;
state->converted = PR_FALSE;
cPtr = fmt;
if (*cPtr != 'c' && *cPtr != 'n' && *cPtr != '[') {
do {
ch = GET(state);
} while (isspace(ch));
UNGET(state, ch);
}
switch (*cPtr) {
case 'c':
if (state->assign) {
cArg = va_arg(state->ap, char *);
}
if (state->width == 0) {
state->width = 1;
}
for (; state->width > 0; state->width--) {
ch = GET(state);
if (ch == EOF) {
return NULL;
} else if (state->assign) {
*cArg++ = ch;
}
}
if (state->assign) {
state->converted = PR_TRUE;
}
break;
case 'p':
case 'd': case 'i': case 'o':
case 'u': case 'x': case 'X':
if (GetInt(state, *cPtr) == PR_FAILURE) {
return NULL;
}
break;
case 'e': case 'E': case 'f':
case 'g': case 'G':
if (GetFloat(state) == PR_FAILURE) {
return NULL;
}
break;
case 'n':
/* do not consume any input */
if (state->assign) {
switch (state->sizeSpec) {
case _PR_size_none:
*va_arg(state->ap, PRIntn *) = state->nChar;
break;
case _PR_size_h:
*va_arg(state->ap, PRInt16 *) = state->nChar;
break;
case _PR_size_l:
*va_arg(state->ap, PRInt32 *) = state->nChar;
break;
case _PR_size_ll:
LL_I2L(*va_arg(state->ap, PRInt64 *), state->nChar);
break;
default:
PR_ASSERT(0);
}
}
break;
case 's':
if (state->width == 0) {
state->width = INT_MAX;
}
if (state->assign) {
cArg = va_arg(state->ap, char *);
}
for (; state->width > 0; state->width--) {
ch = GET(state);
if ((ch == EOF) || isspace(ch)) {
UNGET(state, ch);
break;
}
if (state->assign) {
*cArg++ = ch;
}
}
if (state->assign) {
*cArg = '\0';
state->converted = PR_TRUE;
}
break;
case '%':
ch = GET(state);
if (ch != '%') {
UNGET(state, ch);
return NULL;
}
break;
case '[':
{
PRBool complement = PR_FALSE;
const char *closeBracket;
size_t n;
if (*++cPtr == '^') {
complement = PR_TRUE;
cPtr++;
}
closeBracket = strchr(*cPtr == ']' ? cPtr + 1 : cPtr, ']');
if (closeBracket == NULL) {
return NULL;
}
n = closeBracket - cPtr;
if (state->width == 0) {
state->width = INT_MAX;
}
if (state->assign) {
cArg = va_arg(state->ap, char *);
}
for (; state->width > 0; state->width--) {
ch = GET(state);
if ((ch == EOF)
|| (!complement && !memchr(cPtr, ch, n))
|| (complement && memchr(cPtr, ch, n))) {
UNGET(state, ch);
break;
}
if (state->assign) {
*cArg++ = ch;
}
}
if (state->assign) {
*cArg = '\0';
state->converted = PR_TRUE;
}
cPtr = closeBracket;
}
break;
default:
return NULL;
}
return cPtr;
}
static PRInt32
DoScanf(ScanfState *state, const char *fmt)
{
PRInt32 nConverted = 0;
const char *cPtr;
int ch;
state->nChar = 0;
cPtr = fmt;
while (1) {
if (isspace(*cPtr)) {
/* white space: skip */
do {
cPtr++;
} while (isspace(*cPtr));
do {
ch = GET(state);
} while (isspace(ch));
UNGET(state, ch);
} else if (*cPtr == '%') {
/* format spec: convert */
cPtr++;
state->assign = PR_TRUE;
if (*cPtr == '*') {
cPtr++;
state->assign = PR_FALSE;
}
for (state->width = 0; isdigit(*cPtr); cPtr++) {
state->width = state->width * 10 + *cPtr - '0';
}
state->sizeSpec = _PR_size_none;
if (*cPtr == 'h') {
cPtr++;
state->sizeSpec = _PR_size_h;
} else if (*cPtr == 'l') {
cPtr++;
if (*cPtr == 'l') {
cPtr++;
state->sizeSpec = _PR_size_ll;
} else {
state->sizeSpec = _PR_size_l;
}
} else if (*cPtr == 'L') {
cPtr++;
state->sizeSpec = _PR_size_L;
}
cPtr = Convert(state, cPtr);
if (cPtr == NULL) {
return (nConverted > 0 ? nConverted : EOF);
}
if (state->converted) {
nConverted++;
}
cPtr++;
} else {
/* others: must match */
if (*cPtr == '\0') {
return nConverted;
}
ch = GET(state);
if (ch != *cPtr) {
UNGET(state, ch);
return nConverted;
}
cPtr++;
}
}
}
static int
StringGetChar(void *stream)
{
char *cPtr = *((char **) stream);
if (*cPtr == '\0') {
return EOF;
} else {
*((char **) stream) = cPtr + 1;
return (unsigned char) *cPtr;
}
}
static void
StringUngetChar(void *stream, int ch)
{
char *cPtr = *((char **) stream);
if (ch != EOF) {
*((char **) stream) = cPtr - 1;
}
}
PR_IMPLEMENT(PRInt32)
PR_sscanf(const char *buf, const char *fmt, ...)
{
PRInt32 rv;
ScanfState state;
state.get = &StringGetChar;
state.unget = &StringUngetChar;
state.stream = (void *) &buf;
va_start(state.ap, fmt);
rv = DoScanf(&state, fmt);
va_end(state.ap);
return rv;
}
File diff suppressed because it is too large. Load diff
+103
View File
@@ -0,0 +1,103 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape Portable Runtime (NSPR).
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "primpl.h"
#include <string.h>
/*
** fprintf to a PRFileDesc
*/
PR_IMPLEMENT(PRUint32) PR_fprintf(PRFileDesc* fd, const char *fmt, ...)
{
va_list ap;
PRUint32 rv;
va_start(ap, fmt);
rv = PR_vfprintf(fd, fmt, ap);
va_end(ap);
return rv;
}
PR_IMPLEMENT(PRUint32) PR_vfprintf(PRFileDesc* fd, const char *fmt, va_list ap)
{
/* XXX this could be better */
PRUint32 rv, len;
char* msg = PR_vsmprintf(fmt, ap);
len = strlen(msg);
#ifdef XP_OS2
/*
* OS/2 really needs a \r for every \n.
* In the future we should try to use scatter-gather instead of a
* succession of PR_Write.
*/
if (isatty(PR_FileDesc2NativeHandle(fd))) {
PRUint32 last = 0, idx;
PRInt32 tmp;
rv = 0;
for (idx = 0; idx < len+1; idx++) {
if ((idx - last > 0) && (('\n' == msg[idx]) || (idx == len))) {
tmp = PR_Write(fd, msg + last, idx - last);
if (tmp >= 0) {
rv += tmp;
}
last = idx;
}
/*
* if current character is \n, and
* previous character isn't \r, and
* next character isn't \r
*/
if (('\n' == msg[idx]) &&
((0 == idx) || ('\r' != msg[idx-1])) &&
('\r' != msg[idx+1])) {
/* add extra \r */
tmp = PR_Write(fd, "\r", 1);
if (tmp >= 0) {
rv += tmp;
}
}
}
} else {
rv = PR_Write(fd, msg, len);
}
#else
rv = PR_Write(fd, msg, len);
#endif
PR_DELETE(msg);
return rv;
}