mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-11-15 05:48:33 +00:00
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:
1 parent
855c7b9a77
commit
fff98f6316
1137 files changed
+386873
No files matched your search
@@ -0,0 +1 @@
|
||||
Makefile
|
||||
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
mozilla/nsprpub/pr/src/io
|
||||
@@ -0,0 +1 @@
|
||||
:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot
|
||||
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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) */
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
Reference in new issue
Block a user