summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcvs2hg <devnull@localhost>2001-12-10 22:27:33 +0000
committercvs2hg <devnull@localhost>2001-12-10 22:27:33 +0000
commitdc6bc174e993ea4b6316aabf3d2974c86585d6ae (patch)
tree09c6b1d828292dc907b067746aef389f56f3a956
parenta47df1cefbbbd5c3c9dd2acd10d62cfd112dada7 (diff)
downloadnspr-hg-MOZILLA_0_9_7_BRANCH.tar.gz
-rw-r--r--pr/include/prlog.h253
-rw-r--r--pr/src/io/prlog.c504
-rw-r--r--pr/src/io/prsocket.c1805
3 files changed, 2562 insertions, 0 deletions
diff --git a/pr/include/prlog.h b/pr/include/prlog.h
new file mode 100644
index 00000000..b7a7b5a0
--- /dev/null
+++ b/pr/include/prlog.h
@@ -0,0 +1,253 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * 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 Netscape are
+ * Copyright (C) 1998-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+#ifndef prlog_h___
+#define prlog_h___
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+** prlog.h -- Declare interfaces to NSPR's Logging service
+**
+** NSPR provides a logging service that is used by NSPR itself and is
+** available to client programs.
+**
+** To use the service from a client program, you should create a
+** PRLogModuleInfo structure by calling PR_NewLogModule(). After
+** creating the LogModule, you can write to the log using the PR_LOG()
+** macro.
+**
+** Initialization of the log service is handled by NSPR initialization.
+**
+** At execution time, you must enable the log service. To enable the
+** log service, set the environment variable: NSPR_LOG_MODULES
+** variable.
+**
+** NSPR_LOG_MODULES variable has the form:
+**
+** <moduleName>:<value>[, <moduleName>:<value>]*
+**
+** Where:
+** <moduleName> is the name passed to PR_NewLogModule().
+** <value> is a numeric constant, e.g. 5. This value is the maximum
+** value of a log event, enumerated by PRLogModuleLevel, that you want
+** written to the log.
+**
+** For example: to record all events of greater value than or equal to
+** PR_LOG_ERROR for a LogModule names "gizmo", say:
+**
+** set NSPR_LOG_MODULES=gizmo:2
+**
+** Note that you must specify the numeric value of PR_LOG_ERROR.
+**
+** Special LogModule names are provided for controlling NSPR's log
+** service at execution time. These controls should be set in the
+** NSPR_LOG_MODULES environment variable at execution time to affect
+** NSPR's log service for your application.
+**
+** The special LogModule "all" enables all LogModules. To enable all
+** LogModule calls to PR_LOG(), say:
+**
+** set NSPR_LOG_MODULES=all:5
+**
+** The special LogModule name "sync" tells the NSPR log service to do
+** unbuffered logging.
+**
+** The special LogModule name "bufsize:<size>" tells NSPR to set the
+** log buffer to <size>.
+**
+** The environment variable NSPR_LOG_FILE specifies the log file to use
+** unless the default of "stderr" is acceptable. For MS Windows
+** systems, NSPR_LOG_FILE can be set to a special value: "WinDebug"
+** (case sensitive). This value causes PR_LOG() output to be written
+** using the Windows API OutputDebugString(). OutputDebugString()
+** writes to the debugger window; some people find this helpful.
+**
+**
+** To put log messages in your programs, use the PR_LOG macro:
+**
+** PR_LOG(<module>, <level>, (<printfString>, <args>*));
+**
+** Where <module> is the address of a PRLogModuleInfo structure, and
+** <level> is one of the levels defined by the enumeration:
+** PRLogModuleLevel. <args> is a printf() style of argument list. That
+** is: (fmtstring, ...).
+**
+** Example:
+**
+** main() {
+** PRIntn one = 1;
+** PRLogModuleInfo * myLm = PR_NewLogModule("gizmo");
+** PR_LOG( myLm, PR_LOG_ALWAYS, ("Log this! %d\n", one));
+** return;
+** }
+**
+** Note the use of printf() style arguments as the third agrument(s) to
+** PR_LOG().
+**
+** After compiling and linking you application, set the environment:
+**
+** set NSPR_LOG_MODULES=gizmo:5
+** set NSPR_LOG_FILE=logfile.txt
+**
+** When you execute your application, the string "Log this! 1" will be
+** written to the file "logfile.txt".
+**
+** Note to NSPR engineers: a number of PRLogModuleInfo structures are
+** defined and initialized in prinit.c. See this module for ideas on
+** what to log where.
+**
+*/
+
+typedef enum PRLogModuleLevel {
+ PR_LOG_NONE = 0, /* nothing */
+ PR_LOG_ALWAYS = 1, /* always printed */
+ PR_LOG_ERROR = 2, /* error messages */
+ PR_LOG_WARNING = 3, /* warning messages */
+ PR_LOG_DEBUG = 4, /* debug messages */
+
+ PR_LOG_NOTICE = PR_LOG_DEBUG, /* notice messages */
+ PR_LOG_WARN = PR_LOG_WARNING, /* warning messages */
+ PR_LOG_MIN = PR_LOG_DEBUG, /* minimal debugging messages */
+ PR_LOG_MAX = PR_LOG_DEBUG /* maximal debugging messages */
+} PRLogModuleLevel;
+
+/*
+** One of these structures is created for each module that uses logging.
+** "name" is the name of the module
+** "level" is the debugging level selected for that module
+*/
+typedef struct PRLogModuleInfo {
+ const char *name;
+ PRLogModuleLevel level;
+ struct PRLogModuleInfo *next;
+} PRLogModuleInfo;
+
+/*
+** Create a new log module.
+*/
+NSPR_API(PRLogModuleInfo*) PR_NewLogModule(const char *name);
+
+/*
+** Set the file to use for logging. Returns PR_FALSE if the file cannot
+** be created
+*/
+NSPR_API(PRBool) PR_SetLogFile(const char *name);
+
+/*
+** Set the size of the logging buffer. If "buffer_size" is zero then the
+** logging becomes "synchronous" (or unbuffered).
+*/
+NSPR_API(void) PR_SetLogBuffering(PRIntn buffer_size);
+
+/*
+** Print a string to the log. "fmt" is a PR_snprintf format type. All
+** messages printed to the log are preceeded by the name of the thread
+** and a time stamp. Also, the routine provides a missing newline if one
+** is not provided.
+*/
+NSPR_API(void) PR_LogPrint(const char *fmt, ...);
+
+/*
+** Flush the log to its file.
+*/
+NSPR_API(void) PR_LogFlush(void);
+
+/*
+** Windoze 16 can't support a large static string space for all of the
+** various debugging strings so logging is not enabled for it.
+*/
+#if (defined(DEBUG) || defined(FORCE_PR_LOG)) && !defined(WIN16)
+#define PR_LOGGING 1
+
+#define PR_LOG_TEST(_module,_level) \
+ ((_module)->level >= (_level))
+
+/*
+** Log something.
+** "module" is the address of a PRLogModuleInfo structure
+** "level" is the desired logging level
+** "args" is a variable length list of arguments to print, in the following
+** format: ("printf style format string", ...)
+*/
+#define PR_LOG(_module,_level,_args) \
+ PR_BEGIN_MACRO \
+ if (PR_LOG_TEST(_module,_level)) { \
+ PR_LogPrint _args; \
+ } \
+ PR_END_MACRO
+
+#else /* (defined(DEBUG) || defined(FORCE_PR_LOG)) && !defined(WIN16) */
+
+#undef PR_LOGGING
+#define PR_LOG_TEST(module,level) 0
+#define PR_LOG(module,level,args)
+
+#endif /* (defined(DEBUG) || defined(FORCE_PR_LOG)) && !defined(WIN16) */
+
+#ifndef NO_NSPR_10_SUPPORT
+
+#ifdef PR_LOGGING
+#define PR_LOG_BEGIN PR_LOG
+#define PR_LOG_END PR_LOG
+#define PR_LOG_DEFINE PR_NewLogModule
+#else
+#define PR_LOG_BEGIN(module,level,args)
+#define PR_LOG_END(module,level,args)
+#define PR_LOG_DEFINE(_name) NULL
+#endif /* PR_LOGGING */
+
+#endif /* NO_NSPR_10_SUPPORT */
+
+#if defined(DEBUG)
+
+NSPR_API(void) PR_Assert(const char *s, const char *file, PRIntn ln);
+#define PR_ASSERT(_expr) \
+ ((_expr)?((void)0):PR_Assert(# _expr,__FILE__,__LINE__))
+
+#define PR_NOT_REACHED(_reasonStr) \
+ PR_Assert(_reasonStr,__FILE__,__LINE__)
+
+#else
+
+#define PR_ASSERT(expr) ((void) 0)
+#define PR_NOT_REACHED(reasonStr)
+
+#endif /* defined(DEBUG) */
+
+PR_END_EXTERN_C
+
+#endif /* prlog_h___ */
diff --git a/pr/src/io/prlog.c b/pr/src/io/prlog.c
new file mode 100644
index 00000000..f541a036
--- /dev/null
+++ b/pr/src/io/prlog.c
@@ -0,0 +1,504 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+/*
+ * 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 Netscape are
+ * Copyright (C) 1998-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * 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)
+#define _PUT_LOG(fd, buf, nb) {fputs(buf, 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];
+ 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], "%64[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 == -1) 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)
+{
+ PR_LogFlush();
+
+#ifdef _PR_USE_STDIO_FOR_LOGGING
+ if (logFile && logFile != stdout && logFile != stderr) {
+ fclose(logFile);
+ }
+#else
+ if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) {
+ PR_Close(logFile);
+ }
+#endif
+}
+
+static void _PR_SetLogModuleLevel( PRLogModuleInfo *lm )
+{
+ char *ev;
+
+ ev = PR_GetEnv("NSPR_LOG_MODULES");
+ if (ev && ev[0]) {
+ char module[64];
+ PRIntn evlen = strlen(ev), pos = 0;
+ while (pos < evlen) {
+ PRIntn level = 1, count = 0, delta = 0;
+
+ count = sscanf(&ev[pos], "%64[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 == -1) 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)
+ {
+ logFile = WIN32_DEBUG_FILE;
+ return(PR_TRUE);
+ }
+#endif
+ newLogFile = fopen(file, "w");
+ if (newLogFile) {
+ /* We do buffering ourselves. */
+ setvbuf(newLogFile, NULL, _IONBF, 0);
+ if (logFile && logFile != stdout && logFile != stderr) {
+ fclose(logFile);
+ }
+ logFile = newLogFile;
+ }
+ return (PRBool) (newLogFile != 0);
+#else
+ PRFileDesc *newLogFile;
+
+ newLogFile = PR_Open(file, PR_WRONLY|PR_CREATE_FILE, 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);
+ logBuf = 0;
+
+ 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) {
+#ifdef XP_PC
+ if ( logFile == WIN32_DEBUG_FILE)
+ OutputDebugString( line );
+ else
+ _PUT_LOG(logFile, line, nb);
+#else
+ _PUT_LOG(logFile, line, nb);
+#endif
+ } 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)
+/* Force a trap */
+static void DebugBreak(void) { int *pTrap=NULL; *pTrap = 1; }
+#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
diff --git a/pr/src/io/prsocket.c b/pr/src/io/prsocket.c
new file mode 100644
index 00000000..2483f963
--- /dev/null
+++ b/pr/src/io/prsocket.c
@@ -0,0 +1,1805 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * 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 Netscape are
+ * Copyright (C) 1998-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+#include "primpl.h"
+
+#include <string.h>
+
+/************************************************************************/
+
+/* These two functions are only used in assertions. */
+#if defined(DEBUG)
+
+PRBool IsValidNetAddr(const PRNetAddr *addr)
+{
+ if ((addr != NULL)
+#ifdef XP_UNIX
+ && (addr->raw.family != PR_AF_LOCAL)
+#endif
+ && (addr->raw.family != PR_AF_INET6)
+ && (addr->raw.family != PR_AF_INET)) {
+ return PR_FALSE;
+ }
+ return PR_TRUE;
+}
+
+static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len)
+{
+ /*
+ * The definition of the length of a Unix domain socket address
+ * is not uniform, so we don't check it.
+ */
+ if ((addr != NULL)
+#ifdef XP_UNIX
+ && (addr->raw.family != AF_UNIX)
+#endif
+ && (PR_NETADDR_SIZE(addr) != addr_len)) {
+#if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1
+ /*
+ * In glibc 2.1, struct sockaddr_in6 is 24 bytes. In glibc 2.2
+ * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id
+ * field and is 28 bytes. It is possible for socket functions
+ * to return an addr_len greater than sizeof(struct sockaddr_in6).
+ * We need to allow that. (Bugzilla bug #77264)
+ */
+ if ((PR_AF_INET6 == addr->raw.family)
+ && (sizeof(addr->ipv6) == addr_len)) {
+ return PR_TRUE;
+ }
+#endif
+ /*
+ * The accept(), getsockname(), etc. calls on some platforms
+ * do not set the actual socket address length on return.
+ * In this case, we verifiy addr_len is still the value we
+ * passed in (i.e., sizeof(PRNetAddr)).
+ */
+#if defined(QNX)
+ if (sizeof(PRNetAddr) == addr_len) {
+ return PR_TRUE;
+ }
+#endif
+ return PR_FALSE;
+ }
+ return PR_TRUE;
+}
+
+#endif /* DEBUG */
+
+static PRInt32 PR_CALLBACK SocketWritev(PRFileDesc *fd, const PRIOVec *iov,
+PRInt32 iov_size, PRIntervalTime timeout)
+{
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+ int w = 0;
+ const PRIOVec *tmp_iov;
+#define LOCAL_MAXIOV 8
+ PRIOVec local_iov[LOCAL_MAXIOV];
+ PRIOVec *iov_copy = NULL;
+ int tmp_out;
+ int index, iov_cnt;
+ int count=0, sz = 0; /* 'count' is the return value. */
+
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ return -1;
+ }
+ if (_PR_IO_PENDING(me)) {
+ PR_SetError(PR_IO_PENDING_ERROR, 0);
+ return -1;
+ }
+
+ /*
+ * Assume the first writev will succeed. Copy iov's only on
+ * failure.
+ */
+ tmp_iov = iov;
+ for (index = 0; index < iov_size; index++)
+ sz += iov[index].iov_len;
+
+ iov_cnt = iov_size;
+
+ while (sz > 0) {
+
+ w = _PR_MD_WRITEV(fd, tmp_iov, iov_cnt, timeout);
+ if (w < 0) {
+ count = -1;
+ break;
+ }
+ count += w;
+ if (fd->secret->nonblocking) {
+ break;
+ }
+ sz -= w;
+
+ if (sz > 0) {
+ /* find the next unwritten vector */
+ for ( index = 0, tmp_out = count;
+ tmp_out >= iov[index].iov_len;
+ tmp_out -= iov[index].iov_len, index++){;} /* nothing to execute */
+
+ if (tmp_iov == iov) {
+ /*
+ * The first writev failed so we
+ * must copy iov's around.
+ * Avoid calloc/free if there
+ * are few enough iov's.
+ */
+ if (iov_size - index <= LOCAL_MAXIOV)
+ iov_copy = local_iov;
+ else if ((iov_copy = (PRIOVec *) PR_CALLOC((iov_size - index) *
+ sizeof *iov_copy)) == NULL) {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ return -1;
+ }
+ tmp_iov = iov_copy;
+ }
+
+ PR_ASSERT(tmp_iov == iov_copy);
+
+ /* fill in the first partial read */
+ iov_copy[0].iov_base = &(((char *)iov[index].iov_base)[tmp_out]);
+ iov_copy[0].iov_len = iov[index].iov_len - tmp_out;
+ index++;
+
+ /* copy the remaining vectors */
+ for (iov_cnt=1; index<iov_size; iov_cnt++, index++) {
+ iov_copy[iov_cnt].iov_base = iov[index].iov_base;
+ iov_copy[iov_cnt].iov_len = iov[index].iov_len;
+ }
+ }
+ }
+
+ if (iov_copy != local_iov)
+ PR_DELETE(iov_copy);
+ return count;
+}
+
+/************************************************************************/
+
+PR_IMPLEMENT(PRFileDesc *) PR_ImportTCPSocket(PRInt32 osfd)
+{
+PRFileDesc *fd;
+
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+ fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
+ if (fd != NULL) {
+ _PR_MD_MAKE_NONBLOCK(fd);
+ _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
+ } else
+ _PR_MD_CLOSE_SOCKET(osfd);
+ return(fd);
+}
+
+PR_IMPLEMENT(PRFileDesc *) PR_ImportUDPSocket(PRInt32 osfd)
+{
+PRFileDesc *fd;
+
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+ fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
+ if (fd != NULL) {
+ _PR_MD_MAKE_NONBLOCK(fd);
+ _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
+ } else
+ _PR_MD_CLOSE_SOCKET(osfd);
+ return(fd);
+}
+
+
+static const PRIOMethods* PR_GetSocketPollFdMethods(void);
+
+PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PRInt32 osfd)
+{
+ PRFileDesc *fd;
+
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+
+ fd = _PR_Getfd();
+
+ if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ else
+ {
+ fd->secret->md.osfd = osfd;
+ fd->secret->inheritable = _PR_TRI_FALSE;
+ fd->secret->state = _PR_FILEDESC_OPEN;
+ fd->methods = PR_GetSocketPollFdMethods();
+ }
+
+ return fd;
+} /* PR_CreateSocketPollFD */
+
+PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd)
+{
+ if (NULL == fd)
+ {
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
+ return PR_FAILURE;
+ }
+ fd->secret->state = _PR_FILEDESC_CLOSED;
+ _PR_Putfd(fd);
+ return PR_SUCCESS;
+} /* PR_DestroySocketPollFd */
+
+static PRStatus PR_CALLBACK SocketConnect(
+ PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
+{
+ PRInt32 rv; /* Return value of _PR_MD_CONNECT */
+ const PRNetAddr *addrp = addr;
+#if defined(_PR_INET6)
+ PRNetAddr addrCopy;
+#endif
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ return PR_FAILURE;
+ }
+#if defined(_PR_INET6)
+ if (addr->raw.family == PR_AF_INET6) {
+ addrCopy = *addr;
+ addrCopy.raw.family = AF_INET6;
+ addrp = &addrCopy;
+ }
+#endif
+
+ rv = _PR_MD_CONNECT(fd, addrp, PR_NETADDR_SIZE(addr), timeout);
+ PR_LOG(_pr_io_lm, PR_LOG_MAX, ("connect -> %d", rv));
+ if (rv == 0)
+ return PR_SUCCESS;
+ else
+ return PR_FAILURE;
+}
+
+static PRStatus PR_CALLBACK SocketConnectContinue(
+ PRFileDesc *fd, PRInt16 out_flags)
+{
+ PRInt32 osfd;
+ int err;
+
+ if (out_flags & PR_POLL_NVAL) {
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
+ return PR_FAILURE;
+ }
+ if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0) {
+ PR_ASSERT(out_flags == 0);
+ PR_SetError(PR_IN_PROGRESS_ERROR, 0);
+ return PR_FAILURE;
+ }
+
+ osfd = fd->secret->md.osfd;
+
+#if defined(XP_UNIX)
+
+ err = _MD_unix_get_nonblocking_connect_error(osfd);
+ if (err != 0) {
+ _PR_MD_MAP_CONNECT_ERROR(err);
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+
+#elif defined(WIN32) || defined(WIN16)
+
+#if defined(WIN32)
+ /*
+ * The sleep circumvents a bug in Win32 WinSock.
+ * See Microsoft Knowledge Base article ID: Q165989.
+ */
+ Sleep(0);
+#endif /* WIN32 */
+
+ if (out_flags & PR_POLL_EXCEPT) {
+ int len = sizeof(err);
+ if (getsockopt(osfd, (int)SOL_SOCKET, SO_ERROR, (char *) &err, &len)
+ == SOCKET_ERROR) {
+ _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
+ return PR_FAILURE;
+ }
+ if (err != 0) {
+ _PR_MD_MAP_CONNECT_ERROR(err);
+ } else {
+ PR_SetError(PR_UNKNOWN_ERROR, 0);
+ }
+ return PR_FAILURE;
+ }
+
+ PR_ASSERT(out_flags & PR_POLL_WRITE);
+ return PR_SUCCESS;
+
+#elif defined(XP_OS2)
+
+ if (out_flags & PR_POLL_EXCEPT) {
+ int len = sizeof(err);
+ if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &len)
+ < 0) {
+ _PR_MD_MAP_GETSOCKOPT_ERROR(sock_errno());
+ return PR_FAILURE;
+ }
+ if (err != 0) {
+ _PR_MD_MAP_CONNECT_ERROR(err);
+ } else {
+ PR_SetError(PR_UNKNOWN_ERROR, 0);
+ }
+ return PR_FAILURE;
+ }
+
+ PR_ASSERT(out_flags & PR_POLL_WRITE);
+ return PR_SUCCESS;
+
+#elif defined(XP_MAC)
+
+ err = _MD_mac_get_nonblocking_connect_error(osfd);
+ if (err == -1)
+ return PR_FAILURE;
+ else
+ return PR_SUCCESS;
+
+#elif defined(XP_BEOS)
+
+ err = _MD_beos_get_nonblocking_connect_error(fd);
+ if( err != 0 ) {
+ _PR_MD_MAP_CONNECT_ERROR(err);
+ return PR_FAILURE;
+ }
+ else
+ return PR_SUCCESS;
+
+#else
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+#endif
+}
+
+PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd)
+{
+ /* Find the NSPR layer and invoke its connectcontinue method */
+ PRFileDesc *bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
+
+ if (NULL == bottom) {
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return PR_FAILURE;
+ }
+ return SocketConnectContinue(bottom, pd->out_flags);
+}
+
+static PRFileDesc* PR_CALLBACK SocketAccept(PRFileDesc *fd, PRNetAddr *addr,
+PRIntervalTime timeout)
+{
+ PRInt32 osfd;
+ PRFileDesc *fd2;
+ PRUint32 al;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+#ifdef WINNT
+ PRNetAddr addrCopy;
+#endif
+
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ return 0;
+ }
+ if (_PR_IO_PENDING(me)) {
+ PR_SetError(PR_IO_PENDING_ERROR, 0);
+ return 0;
+ }
+
+#ifdef WINNT
+ if (addr == NULL) {
+ addr = &addrCopy;
+ }
+#endif
+ al = sizeof(PRNetAddr);
+ osfd = _PR_MD_ACCEPT(fd, addr, &al, timeout);
+ if (osfd == -1)
+ return 0;
+
+ fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
+ if (!fd2) {
+ _PR_MD_CLOSE_SOCKET(osfd);
+ return NULL;
+ }
+
+ fd2->secret->nonblocking = fd->secret->nonblocking;
+ fd2->secret->inheritable = fd->secret->inheritable;
+#ifdef WINNT
+ if (!fd2->secret->nonblocking && fd2->secret->inheritable != _PR_TRI_TRUE) {
+ /*
+ * The new socket has been associated with an I/O
+ * completion port. There is no going back.
+ */
+ fd2->secret->md.io_model_committed = PR_TRUE;
+ }
+ PR_ASSERT(al == PR_NETADDR_SIZE(addr));
+ fd2->secret->md.accepted_socket = PR_TRUE;
+ memcpy(&fd2->secret->md.peer_addr, addr, al);
+#endif
+
+ /*
+ * On some platforms, the new socket created by accept()
+ * inherits the nonblocking (or overlapped io) attribute
+ * of the listening socket. As an optimization, these
+ * platforms can skip the following _PR_MD_MAKE_NONBLOCK
+ * call.
+ *
+ * On Mac, we MUST make this call, because _PR_MD_MAKE_NONBLOCK
+ * (which maps to _MD_makenonblock, see macsockotpt.c)
+ * installs the async notifier routine needed to make blocking
+ * I/O work properly.
+ */
+#if !defined(SOLARIS) && !defined(IRIX) && !defined(WINNT)
+ _PR_MD_MAKE_NONBLOCK(fd2);
+#endif
+
+#ifdef _PR_INET6
+ if (addr && (AF_INET6 == addr->raw.family))
+ addr->raw.family = PR_AF_INET6;
+#endif
+ PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+ PR_ASSERT(IsValidNetAddrLen(addr, al) == PR_TRUE);
+
+ return fd2;
+}
+
+#ifdef WINNT
+PR_IMPLEMENT(PRFileDesc*) PR_NTFast_Accept(PRFileDesc *fd, PRNetAddr *addr,
+PRIntervalTime timeout)
+{
+ PRInt32 osfd;
+ PRFileDesc *fd2;
+ PRIntn al;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+ PRNetAddr addrCopy;
+
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ return 0;
+ }
+ if (_PR_IO_PENDING(me)) {
+ PR_SetError(PR_IO_PENDING_ERROR, 0);
+ return 0;
+ }
+
+ if (addr == NULL) {
+ addr = &addrCopy;
+ }
+ al = PR_NETADDR_SIZE(addr);
+ osfd = _PR_MD_FAST_ACCEPT(fd, addr, &al, timeout, PR_TRUE, NULL, NULL);
+ if (osfd == -1) {
+ return 0;
+ }
+
+ fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
+ if (!fd2) {
+ _PR_MD_CLOSE_SOCKET(osfd);
+ } else {
+ fd2->secret->nonblocking = fd->secret->nonblocking;
+ fd2->secret->md.io_model_committed = PR_TRUE;
+ PR_ASSERT(al == PR_NETADDR_SIZE(addr));
+ fd2->secret->md.accepted_socket = PR_TRUE;
+ memcpy(&fd2->secret->md.peer_addr, addr, al);
+#ifdef _PR_INET6
+ if (AF_INET6 == addr->raw.family)
+ addr->raw.family = PR_AF_INET6;
+#endif
+ }
+ return fd2;
+}
+#endif /* WINNT */
+
+
+static PRStatus PR_CALLBACK SocketBind(PRFileDesc *fd, const PRNetAddr *addr)
+{
+ PRInt32 result;
+ const PRNetAddr *addrp = addr;
+#if defined(_PR_INET6)
+ PRNetAddr addrCopy;
+#endif
+
+ PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+
+#ifdef XP_UNIX
+ if (addr->raw.family == AF_UNIX) {
+ /* Disallow relative pathnames */
+ if (addr->local.path[0] != '/') {
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return PR_FAILURE;
+ }
+ }
+#endif /* XP_UNIX */
+
+#if defined(_PR_INET6)
+ if (addr->raw.family == PR_AF_INET6) {
+ addrCopy = *addr;
+ addrCopy.raw.family = AF_INET6;
+ addrp = &addrCopy;
+ }
+#endif
+ result = _PR_MD_BIND(fd, addrp, PR_NETADDR_SIZE(addr));
+ if (result < 0) {
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
+
+static PRStatus PR_CALLBACK SocketListen(PRFileDesc *fd, PRIntn backlog)
+{
+ PRInt32 result;
+
+ result = _PR_MD_LISTEN(fd, backlog);
+ if (result < 0) {
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
+
+static PRStatus PR_CALLBACK SocketShutdown(PRFileDesc *fd, PRIntn how)
+{
+ PRInt32 result;
+
+ result = _PR_MD_SHUTDOWN(fd, how);
+ if (result < 0) {
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
+
+static PRInt32 PR_CALLBACK SocketRecv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
+PRIntervalTime timeout)
+{
+ PRInt32 rv;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+
+ if ((flags != 0) && (flags != PR_MSG_PEEK)) {
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return -1;
+ }
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ return -1;
+ }
+ if (_PR_IO_PENDING(me)) {
+ PR_SetError(PR_IO_PENDING_ERROR, 0);
+ return -1;
+ }
+
+ PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv: fd=%p osfd=%d buf=%p amount=%d flags=%d",
+ fd, fd->secret->md.osfd, buf, amount, flags));
+
+#ifdef _PR_HAVE_PEEK_BUFFER
+ if (fd->secret->peekBytes != 0) {
+ rv = (amount < fd->secret->peekBytes) ?
+ amount : fd->secret->peekBytes;
+ memcpy(buf, fd->secret->peekBuffer, rv);
+ if (flags == 0) {
+ /* consume the bytes in the peek buffer */
+ fd->secret->peekBytes -= rv;
+ if (fd->secret->peekBytes != 0) {
+ memmove(fd->secret->peekBuffer,
+ fd->secret->peekBuffer + rv,
+ fd->secret->peekBytes);
+ }
+ }
+ return rv;
+ }
+
+ /* allocate peek buffer, if necessary */
+ if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) {
+ PR_ASSERT(0 == fd->secret->peekBytes);
+ /* impose a max size on the peek buffer */
+ if (amount > _PR_PEEK_BUFFER_MAX) {
+ amount = _PR_PEEK_BUFFER_MAX;
+ }
+ if (fd->secret->peekBufSize < amount) {
+ if (fd->secret->peekBuffer) {
+ PR_Free(fd->secret->peekBuffer);
+ }
+ fd->secret->peekBufSize = amount;
+ fd->secret->peekBuffer = PR_Malloc(amount);
+ if (NULL == fd->secret->peekBuffer) {
+ fd->secret->peekBufSize = 0;
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ return -1;
+ }
+ }
+ }
+#endif
+
+ rv = _PR_MD_RECV(fd, buf, amount, flags, timeout);
+ PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv -> %d, error = %d, os error = %d",
+ rv, PR_GetError(), PR_GetOSError()));
+
+#ifdef _PR_HAVE_PEEK_BUFFER
+ if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) {
+ if (rv > 0) {
+ memcpy(fd->secret->peekBuffer, buf, rv);
+ fd->secret->peekBytes = rv;
+ }
+ }
+#endif
+
+ return rv;
+}
+
+static PRInt32 PR_CALLBACK SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount)
+{
+ return SocketRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
+}
+
+static PRInt32 PR_CALLBACK SocketSend(PRFileDesc *fd, const void *buf, PRInt32 amount,
+PRIntn flags, PRIntervalTime timeout)
+{
+ 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);
+ return -1;
+ }
+ if (_PR_IO_PENDING(me)) {
+ PR_SetError(PR_IO_PENDING_ERROR, 0);
+ return -1;
+ }
+
+ count = 0;
+ while (amount > 0) {
+ PR_LOG(_pr_io_lm, PR_LOG_MAX,
+ ("send: fd=%p osfd=%d buf=%p amount=%d",
+ fd, fd->secret->md.osfd, buf, amount));
+ temp = _PR_MD_SEND(fd, buf, amount, flags, timeout);
+ 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, ("send -> %d", count));
+ return count;
+}
+
+static PRInt32 PR_CALLBACK SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 amount)
+{
+ return SocketSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
+}
+
+static PRStatus PR_CALLBACK SocketClose(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_SOCKET(fd->secret->md.osfd) < 0) {
+ return PR_FAILURE;
+ }
+ fd->secret->state = _PR_FILEDESC_CLOSED;
+ }
+
+#ifdef _PR_HAVE_PEEK_BUFFER
+ if (fd->secret->peekBuffer) {
+ PR_ASSERT(fd->secret->peekBufSize > 0);
+ PR_DELETE(fd->secret->peekBuffer);
+ fd->secret->peekBufSize = 0;
+ fd->secret->peekBytes = 0;
+ }
+#endif
+
+ PR_FreeFileDesc(fd);
+ return PR_SUCCESS;
+}
+
+static PRInt32 PR_CALLBACK SocketAvailable(PRFileDesc *fd)
+{
+ PRInt32 rv;
+#ifdef _PR_HAVE_PEEK_BUFFER
+ if (fd->secret->peekBytes != 0) {
+ return fd->secret->peekBytes;
+ }
+#endif
+ rv = _PR_MD_SOCKETAVAILABLE(fd);
+ return rv;
+}
+
+static PRInt64 PR_CALLBACK SocketAvailable64(PRFileDesc *fd)
+{
+ PRInt64 rv;
+#ifdef _PR_HAVE_PEEK_BUFFER
+ if (fd->secret->peekBytes != 0) {
+ LL_I2L(rv, fd->secret->peekBytes);
+ return rv;
+ }
+#endif
+ LL_I2L(rv, _PR_MD_SOCKETAVAILABLE(fd));
+ return rv;
+}
+
+static PRStatus PR_CALLBACK SocketSync(PRFileDesc *fd)
+{
+#if defined(XP_MAC)
+#pragma unused (fd)
+#endif
+
+ return PR_SUCCESS;
+}
+
+static PRInt32 PR_CALLBACK SocketSendTo(
+ PRFileDesc *fd, const void *buf, PRInt32 amount,
+ PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
+{
+ PRInt32 temp, count;
+ const PRNetAddr *addrp = addr;
+#if defined(_PR_INET6)
+ PRNetAddr addrCopy;
+#endif
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ return -1;
+ }
+ if (_PR_IO_PENDING(me)) {
+ PR_SetError(PR_IO_PENDING_ERROR, 0);
+ return -1;
+ }
+
+ PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+#if defined(_PR_INET6)
+ if (addr->raw.family == PR_AF_INET6) {
+ addrCopy = *addr;
+ addrCopy.raw.family = AF_INET6;
+ addrp = &addrCopy;
+ }
+#endif
+
+ count = 0;
+ while (amount > 0) {
+ temp = _PR_MD_SENDTO(fd, buf, amount, flags,
+ addrp, PR_NETADDR_SIZE(addr), timeout);
+ if (temp < 0) {
+ count = -1;
+ break;
+ }
+ count += temp;
+ if (fd->secret->nonblocking) {
+ break;
+ }
+ buf = (const void*) ((const char*)buf + temp);
+ amount -= temp;
+ }
+ return count;
+}
+
+static PRInt32 PR_CALLBACK SocketRecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
+PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
+{
+ PRInt32 rv;
+ PRUint32 al;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ return -1;
+ }
+ if (_PR_IO_PENDING(me)) {
+ PR_SetError(PR_IO_PENDING_ERROR, 0);
+ return -1;
+ }
+
+ al = sizeof(PRNetAddr);
+ rv = _PR_MD_RECVFROM(fd, buf, amount, flags, addr, &al, timeout);
+#ifdef _PR_INET6
+ if (addr && (AF_INET6 == addr->raw.family))
+ addr->raw.family = PR_AF_INET6;
+#endif
+ return rv;
+}
+
+static PRInt32 PR_CALLBACK SocketAcceptRead(PRFileDesc *sd, PRFileDesc **nd,
+PRNetAddr **raddr, void *buf, PRInt32 amount,
+PRIntervalTime timeout)
+{
+ PRInt32 rv;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ return -1;
+ }
+ if (_PR_IO_PENDING(me)) {
+ PR_SetError(PR_IO_PENDING_ERROR, 0);
+ return -1;
+ }
+ /* The socket must be in blocking mode. */
+ if (sd->secret->nonblocking) {
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return -1;
+ }
+ *nd = NULL;
+
+#if defined(WINNT)
+ {
+ PRInt32 newSock;
+ PRNetAddr *raddrCopy;
+
+ if (raddr == NULL) {
+ raddr = &raddrCopy;
+ }
+ rv = _PR_MD_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout);
+ if (rv < 0) {
+ rv = -1;
+ } else {
+ /* Successfully accepted and read; create the new PRFileDesc */
+ *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
+ if (*nd == 0) {
+ _PR_MD_CLOSE_SOCKET(newSock);
+ /* PR_AllocFileDesc() has invoked PR_SetError(). */
+ rv = -1;
+ } else {
+ (*nd)->secret->md.io_model_committed = PR_TRUE;
+ (*nd)->secret->md.accepted_socket = PR_TRUE;
+ memcpy(&(*nd)->secret->md.peer_addr, *raddr,
+ PR_NETADDR_SIZE(*raddr));
+#ifdef _PR_INET6
+ if (AF_INET6 == *raddr->raw.family)
+ *raddr->raw.family = PR_AF_INET6;
+#endif
+ }
+ }
+ }
+#else
+ rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
+#endif
+ return rv;
+}
+
+#ifdef WINNT
+PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead(PRFileDesc *sd, PRFileDesc **nd,
+PRNetAddr **raddr, void *buf, PRInt32 amount,
+PRIntervalTime timeout)
+{
+ PRInt32 rv;
+ PRInt32 newSock;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+ PRNetAddr *raddrCopy;
+
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ return -1;
+ }
+ if (_PR_IO_PENDING(me)) {
+ PR_SetError(PR_IO_PENDING_ERROR, 0);
+ return -1;
+ }
+ *nd = NULL;
+
+ if (raddr == NULL) {
+ raddr = &raddrCopy;
+ }
+ rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount,
+ timeout, PR_TRUE, NULL, NULL);
+ if (rv < 0) {
+ rv = -1;
+ } else {
+ /* Successfully accepted and read; create the new PRFileDesc */
+ *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
+ if (*nd == 0) {
+ _PR_MD_CLOSE_SOCKET(newSock);
+ /* PR_AllocFileDesc() has invoked PR_SetError(). */
+ rv = -1;
+ } else {
+ (*nd)->secret->md.io_model_committed = PR_TRUE;
+ (*nd)->secret->md.accepted_socket = PR_TRUE;
+ memcpy(&(*nd)->secret->md.peer_addr, *raddr,
+ PR_NETADDR_SIZE(*raddr));
+#ifdef _PR_INET6
+ if (AF_INET6 == *raddr->raw.family)
+ *raddr->raw.family = PR_AF_INET6;
+#endif
+ }
+ }
+ return rv;
+}
+
+PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead_WithTimeoutCallback(
+PRFileDesc *sd, PRFileDesc **nd,
+PRNetAddr **raddr, void *buf, PRInt32 amount,
+PRIntervalTime timeout,
+_PR_AcceptTimeoutCallback callback,
+void *callbackArg)
+{
+ PRInt32 rv;
+ PRInt32 newSock;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+ PRNetAddr *raddrCopy;
+
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ return -1;
+ }
+ if (_PR_IO_PENDING(me)) {
+ PR_SetError(PR_IO_PENDING_ERROR, 0);
+ return -1;
+ }
+ *nd = NULL;
+
+ if (raddr == NULL) {
+ raddr = &raddrCopy;
+ }
+ rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount,
+ timeout, PR_TRUE, callback, callbackArg);
+ if (rv < 0) {
+ rv = -1;
+ } else {
+ /* Successfully accepted and read; create the new PRFileDesc */
+ *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
+ if (*nd == 0) {
+ _PR_MD_CLOSE_SOCKET(newSock);
+ /* PR_AllocFileDesc() has invoked PR_SetError(). */
+ rv = -1;
+ } else {
+ (*nd)->secret->md.io_model_committed = PR_TRUE;
+ (*nd)->secret->md.accepted_socket = PR_TRUE;
+ memcpy(&(*nd)->secret->md.peer_addr, *raddr,
+ PR_NETADDR_SIZE(*raddr));
+#ifdef _PR_INET6
+ if (AF_INET6 == *raddr->raw.family)
+ *raddr->raw.family = PR_AF_INET6;
+#endif
+ }
+ }
+ return rv;
+}
+#endif /* WINNT */
+
+#ifdef WINNT
+PR_IMPLEMENT(void)
+PR_NTFast_UpdateAcceptContext(PRFileDesc *socket, PRFileDesc *acceptSocket)
+{
+ _PR_MD_UPDATE_ACCEPT_CONTEXT(
+ socket->secret->md.osfd, acceptSocket->secret->md.osfd);
+}
+#endif /* WINNT */
+
+static PRInt32 PR_CALLBACK SocketSendFile(
+ PRFileDesc *sd, PRSendFileData *sfd,
+ PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+ PRInt32 rv;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ return -1;
+ }
+ if (_PR_IO_PENDING(me)) {
+ PR_SetError(PR_IO_PENDING_ERROR, 0);
+ return -1;
+ }
+ /* The socket must be in blocking mode. */
+ if (sd->secret->nonblocking) {
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return -1;
+ }
+#if defined(WINNT)
+ rv = _PR_MD_SENDFILE(sd, sfd, flags, timeout);
+ if ((rv >= 0) && (flags == PR_TRANSMITFILE_CLOSE_SOCKET)) {
+ /*
+ * This should be kept the same as SocketClose, except
+ * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should
+ * not be called because the socket will be recycled.
+ */
+ PR_FreeFileDesc(sd);
+ }
+#else
+ rv = PR_EmulateSendFile(sd, sfd, flags, timeout);
+#endif /* WINNT */
+
+ return rv;
+}
+
+static PRInt32 PR_CALLBACK SocketTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
+const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
+PRIntervalTime timeout)
+{
+ PRSendFileData sfd;
+
+ sfd.fd = fd;
+ sfd.file_offset = 0;
+ sfd.file_nbytes = 0;
+ sfd.header = headers;
+ sfd.hlen = hlen;
+ sfd.trailer = NULL;
+ sfd.tlen = 0;
+
+ return(SocketSendFile(sd, &sfd, flags, timeout));
+}
+
+static PRStatus PR_CALLBACK SocketGetName(PRFileDesc *fd, PRNetAddr *addr)
+{
+ PRInt32 result;
+ PRUint32 addrlen;
+
+ addrlen = sizeof(PRNetAddr);
+ result = _PR_MD_GETSOCKNAME(fd, addr, &addrlen);
+ if (result < 0) {
+ return PR_FAILURE;
+ }
+#ifdef _PR_INET6
+ if (AF_INET6 == addr->raw.family)
+ addr->raw.family = PR_AF_INET6;
+#endif
+ PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+ PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE);
+ return PR_SUCCESS;
+}
+
+static PRStatus PR_CALLBACK SocketGetPeerName(PRFileDesc *fd, PRNetAddr *addr)
+{
+ PRInt32 result;
+ PRUint32 addrlen;
+
+ addrlen = sizeof(PRNetAddr);
+ result = _PR_MD_GETPEERNAME(fd, addr, &addrlen);
+ if (result < 0) {
+ return PR_FAILURE;
+ }
+#ifdef _PR_INET6
+ if (AF_INET6 == addr->raw.family)
+ addr->raw.family = PR_AF_INET6;
+#endif
+ PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+ PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE);
+ return PR_SUCCESS;
+}
+
+static PRInt16 PR_CALLBACK SocketPoll(
+ PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
+{
+#ifdef XP_MAC
+#pragma unused( fd, in_flags )
+#endif
+ *out_flags = 0;
+ return in_flags;
+} /* SocketPoll */
+
+static PRIOMethods tcpMethods = {
+ PR_DESC_SOCKET_TCP,
+ SocketClose,
+ SocketRead,
+ SocketWrite,
+ SocketAvailable,
+ SocketAvailable64,
+ SocketSync,
+ (PRSeekFN)_PR_InvalidInt,
+ (PRSeek64FN)_PR_InvalidInt64,
+ (PRFileInfoFN)_PR_InvalidStatus,
+ (PRFileInfo64FN)_PR_InvalidStatus,
+ SocketWritev,
+ SocketConnect,
+ SocketAccept,
+ SocketBind,
+ SocketListen,
+ SocketShutdown,
+ SocketRecv,
+ SocketSend,
+ (PRRecvfromFN)_PR_InvalidInt,
+ (PRSendtoFN)_PR_InvalidInt,
+ SocketPoll,
+ SocketAcceptRead,
+ SocketTransmitFile,
+ SocketGetName,
+ SocketGetPeerName,
+ (PRReservedFN)_PR_InvalidInt,
+ (PRReservedFN)_PR_InvalidInt,
+ _PR_SocketGetSocketOption,
+ _PR_SocketSetSocketOption,
+ SocketSendFile,
+ SocketConnectContinue,
+ (PRReservedFN)_PR_InvalidInt,
+ (PRReservedFN)_PR_InvalidInt,
+ (PRReservedFN)_PR_InvalidInt,
+ (PRReservedFN)_PR_InvalidInt
+};
+
+static PRIOMethods udpMethods = {
+ PR_DESC_SOCKET_UDP,
+ SocketClose,
+ SocketRead,
+ SocketWrite,
+ SocketAvailable,
+ SocketAvailable64,
+ SocketSync,
+ (PRSeekFN)_PR_InvalidInt,
+ (PRSeek64FN)_PR_InvalidInt64,
+ (PRFileInfoFN)_PR_InvalidStatus,
+ (PRFileInfo64FN)_PR_InvalidStatus,
+ SocketWritev,
+ SocketConnect,
+ (PRAcceptFN)_PR_InvalidDesc,
+ SocketBind,
+ SocketListen,
+ SocketShutdown,
+ SocketRecv,
+ SocketSend,
+ SocketRecvFrom,
+ SocketSendTo,
+ SocketPoll,
+ (PRAcceptreadFN)_PR_InvalidInt,
+ (PRTransmitfileFN)_PR_InvalidInt,
+ SocketGetName,
+ SocketGetPeerName,
+ (PRReservedFN)_PR_InvalidInt,
+ (PRReservedFN)_PR_InvalidInt,
+ _PR_SocketGetSocketOption,
+ _PR_SocketSetSocketOption,
+ (PRSendfileFN)_PR_InvalidInt,
+ (PRConnectcontinueFN)_PR_InvalidStatus,
+ (PRReservedFN)_PR_InvalidInt,
+ (PRReservedFN)_PR_InvalidInt,
+ (PRReservedFN)_PR_InvalidInt,
+ (PRReservedFN)_PR_InvalidInt
+};
+
+
+static PRIOMethods socketpollfdMethods = {
+ (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,
+ SocketPoll,
+ (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_GetTCPMethods()
+{
+ return &tcpMethods;
+}
+
+PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods()
+{
+ return &udpMethods;
+}
+
+static const PRIOMethods* PR_GetSocketPollFdMethods()
+{
+ return &socketpollfdMethods;
+} /* PR_GetSocketPollFdMethods */
+
+#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
+PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd);
+
+#if defined(_PR_INET6_PROBE)
+
+PR_EXTERN(PRBool) _pr_ipv6_is_present;
+
+PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket()
+{
+PRInt32 osfd;
+
+ osfd = _PR_MD_SOCKET(AF_INET6, SOCK_STREAM, 0);
+ if (osfd != -1) {
+ _PR_MD_CLOSE_SOCKET(osfd);
+ return PR_TRUE;
+ }
+ return PR_FALSE;
+}
+#endif /* _PR_INET6_PROBE */
+
+#endif
+
+PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
+{
+ PRInt32 osfd;
+ PRFileDesc *fd;
+ PRInt32 tmp_domain = domain;
+
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+ if (PR_AF_INET != domain
+ && PR_AF_INET6 != domain
+#if defined(XP_UNIX)
+ && PR_AF_LOCAL != domain
+#endif
+ ) {
+ PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
+ return NULL;
+ }
+
+#if defined(_PR_INET6_PROBE)
+ if (PR_AF_INET6 == domain) {
+ if (_pr_ipv6_is_present == PR_FALSE)
+ domain = AF_INET;
+ else
+ domain = AF_INET6;
+ }
+#elif defined(_PR_INET6)
+ if (PR_AF_INET6 == domain)
+ domain = AF_INET6;
+#else
+ if (PR_AF_INET6 == domain)
+ domain = AF_INET;
+#endif /* _PR_INET6 */
+ osfd = _PR_MD_SOCKET(domain, type, proto);
+ if (osfd == -1) {
+ return 0;
+ }
+ if (type == SOCK_STREAM)
+ fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
+ else
+ fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
+ /*
+ * Make the sockets non-blocking
+ */
+ if (fd != NULL) {
+ _PR_MD_MAKE_NONBLOCK(fd);
+ _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE);
+#if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
+ /*
+ * For platforms with no support for IPv6
+ * create layered socket for IPv4-mapped IPv6 addresses
+ */
+ if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) {
+ if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) {
+ PR_Close(fd);
+ fd = NULL;
+ }
+ }
+#endif
+ } else
+ _PR_MD_CLOSE_SOCKET(osfd);
+
+ return fd;
+}
+
+PR_IMPLEMENT(PRFileDesc *) PR_NewTCPSocket(void)
+{
+ PRInt32 domain = AF_INET;
+
+ return PR_Socket(domain, SOCK_STREAM, 0);
+}
+
+PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void)
+{
+ PRInt32 domain = AF_INET;
+
+ return PR_Socket(domain, SOCK_DGRAM, 0);
+}
+
+PR_IMPLEMENT(PRFileDesc *) PR_OpenTCPSocket(PRIntn af)
+{
+ return PR_Socket(af, SOCK_STREAM, 0);
+}
+
+PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af)
+{
+ return PR_Socket(af, SOCK_DGRAM, 0);
+}
+
+PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *f[])
+{
+#ifdef XP_UNIX
+ PRInt32 rv, osfd[2];
+
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+
+ rv = _PR_MD_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, osfd);
+ if (rv == -1) {
+ return PR_FAILURE;
+ }
+
+ f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
+ if (!f[0]) {
+ _PR_MD_CLOSE_SOCKET(osfd[0]);
+ _PR_MD_CLOSE_SOCKET(osfd[1]);
+ /* PR_AllocFileDesc() has invoked PR_SetError(). */
+ return PR_FAILURE;
+ }
+ f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
+ if (!f[1]) {
+ PR_Close(f[0]);
+ _PR_MD_CLOSE_SOCKET(osfd[1]);
+ /* PR_AllocFileDesc() has invoked PR_SetError(). */
+ return PR_FAILURE;
+ }
+ _PR_MD_MAKE_NONBLOCK(f[0]);
+ _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE);
+ _PR_MD_MAKE_NONBLOCK(f[1]);
+ _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE);
+ return PR_SUCCESS;
+#elif defined(WINNT)
+ /*
+ * A socket pair is often used for interprocess communication,
+ * so we need to make sure neither socket is associated with
+ * the I/O completion port; otherwise it can't be used by a
+ * child process.
+ *
+ * The default implementation below cannot be used for NT
+ * because PR_Accept would have associated the I/O completion
+ * port with the listening and accepted sockets.
+ */
+ SOCKET listenSock;
+ SOCKET osfd[2];
+ struct sockaddr_in selfAddr;
+ int addrLen;
+
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+
+ osfd[0] = osfd[1] = INVALID_SOCKET;
+ listenSock = socket(AF_INET, SOCK_STREAM, 0);
+ if (listenSock == INVALID_SOCKET) {
+ goto failed;
+ }
+ selfAddr.sin_family = AF_INET;
+ selfAddr.sin_port = 0;
+ selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* BugZilla: 35408 */
+ addrLen = sizeof(selfAddr);
+ if (bind(listenSock, (struct sockaddr *) &selfAddr,
+ addrLen) == SOCKET_ERROR) {
+ goto failed;
+ }
+ if (getsockname(listenSock, (struct sockaddr *) &selfAddr,
+ &addrLen) == SOCKET_ERROR) {
+ goto failed;
+ }
+ if (listen(listenSock, 5) == SOCKET_ERROR) {
+ goto failed;
+ }
+ osfd[0] = socket(AF_INET, SOCK_STREAM, 0);
+ if (osfd[0] == INVALID_SOCKET) {
+ goto failed;
+ }
+ selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ /*
+ * Only a thread is used to do the connect and accept.
+ * I am relying on the fact that connect returns
+ * successfully as soon as the connect request is put
+ * into the listen queue (but before accept is called).
+ * This is the behavior of the BSD socket code. If
+ * connect does not return until accept is called, we
+ * will need to create another thread to call connect.
+ */
+ if (connect(osfd[0], (struct sockaddr *) &selfAddr,
+ addrLen) == SOCKET_ERROR) {
+ goto failed;
+ }
+ osfd[1] = accept(listenSock, NULL, NULL);
+ if (osfd[1] == INVALID_SOCKET) {
+ goto failed;
+ }
+ closesocket(listenSock);
+
+ f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
+ if (!f[0]) {
+ closesocket(osfd[0]);
+ closesocket(osfd[1]);
+ /* PR_AllocFileDesc() has invoked PR_SetError(). */
+ return PR_FAILURE;
+ }
+ f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
+ if (!f[1]) {
+ PR_Close(f[0]);
+ closesocket(osfd[1]);
+ /* PR_AllocFileDesc() has invoked PR_SetError(). */
+ return PR_FAILURE;
+ }
+ _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE);
+ _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE);
+ return PR_SUCCESS;
+
+failed:
+ if (listenSock != INVALID_SOCKET) {
+ closesocket(listenSock);
+ }
+ if (osfd[0] != INVALID_SOCKET) {
+ closesocket(osfd[0]);
+ }
+ if (osfd[1] != INVALID_SOCKET) {
+ closesocket(osfd[1]);
+ }
+ return PR_FAILURE;
+#else /* not Unix or NT */
+ /*
+ * default implementation
+ */
+ PRFileDesc *listenSock;
+ PRNetAddr selfAddr;
+ PRUint16 port;
+
+ f[0] = f[1] = NULL;
+ listenSock = PR_NewTCPSocket();
+ if (listenSock == NULL) {
+ goto failed;
+ }
+ PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */
+ if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) {
+ goto failed;
+ }
+ if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) {
+ goto failed;
+ }
+ port = ntohs(selfAddr.inet.port);
+ if (PR_Listen(listenSock, 5) == PR_FAILURE) {
+ goto failed;
+ }
+ f[0] = PR_NewTCPSocket();
+ if (f[0] == NULL) {
+ goto failed;
+ }
+ PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr);
+
+ /*
+ * Only a thread is used to do the connect and accept.
+ * I am relying on the fact that PR_Connect returns
+ * successfully as soon as the connect request is put
+ * into the listen queue (but before PR_Accept is called).
+ * This is the behavior of the BSD socket code. If
+ * connect does not return until accept is called, we
+ * will need to create another thread to call connect.
+ */
+ if (PR_Connect(f[0], &selfAddr, PR_INTERVAL_NO_TIMEOUT)
+ == PR_FAILURE) {
+ goto failed;
+ }
+ f[1] = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
+ if (f[1] == NULL) {
+ goto failed;
+ }
+ PR_Close(listenSock);
+ return PR_SUCCESS;
+
+failed:
+ if (listenSock) {
+ PR_Close(listenSock);
+ }
+ if (f[0]) {
+ PR_Close(f[0]);
+ }
+ return PR_FAILURE;
+#endif
+}
+
+PR_IMPLEMENT(PRInt32)
+PR_FileDesc2NativeHandle(PRFileDesc *fd)
+{
+ if (fd) {
+ /*
+ * The fd may be layered. Chase the links to the
+ * bottom layer to get the osfd.
+ */
+ PRFileDesc *bottom = fd;
+ while (bottom->lower != NULL) {
+ bottom = bottom->lower;
+ }
+ return bottom->secret->md.osfd;
+ } else {
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return -1;
+ }
+}
+
+PR_IMPLEMENT(void)
+PR_ChangeFileDescNativeHandle(PRFileDesc *fd, PRInt32 handle)
+{
+ if (fd)
+ fd->secret->md.osfd = handle;
+}
+
+/*
+** Select compatibility
+**
+*/
+
+PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set)
+{
+ memset(set, 0, sizeof(PR_fd_set));
+}
+
+PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set)
+{
+ PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC );
+
+ set->harray[set->hsize++] = fh;
+}
+
+PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set)
+{
+ PRUint32 index, index2;
+
+ for (index = 0; index<set->hsize; index++)
+ if (set->harray[index] == fh) {
+ for (index2=index; index2 < (set->hsize-1); index2++) {
+ set->harray[index2] = set->harray[index2+1];
+ }
+ set->hsize--;
+ break;
+ }
+}
+
+PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set)
+{
+ PRUint32 index;
+ for (index = 0; index<set->hsize; index++)
+ if (set->harray[index] == fh) {
+ return 1;
+ }
+ return 0;
+}
+
+PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set *set)
+{
+ PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC );
+
+ set->narray[set->nsize++] = fd;
+}
+
+PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set *set)
+{
+ PRUint32 index, index2;
+
+ for (index = 0; index<set->nsize; index++)
+ if (set->narray[index] == fd) {
+ for (index2=index; index2 < (set->nsize-1); index2++) {
+ set->narray[index2] = set->narray[index2+1];
+ }
+ set->nsize--;
+ break;
+ }
+}
+
+PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set *set)
+{
+ PRUint32 index;
+ for (index = 0; index<set->nsize; index++)
+ if (set->narray[index] == fd) {
+ return 1;
+ }
+ return 0;
+}
+
+
+#if !defined(NEED_SELECT)
+#if !defined(XP_MAC)
+#include "obsolete/probslet.h"
+#else
+#include "probslet.h"
+#endif
+
+#define PD_INCR 20
+
+static PRPollDesc *_pr_setfd(
+ PR_fd_set *set, PRInt16 flags, PRPollDesc *polldesc)
+{
+ PRUintn fsidx, pdidx;
+ PRPollDesc *poll = polldesc;
+
+ if (NULL == set) return poll;
+
+ /* First set the pr file handle osfds */
+ for (fsidx = 0; fsidx < set->hsize; fsidx++)
+ {
+ for (pdidx = 0; 1; pdidx++)
+ {
+ if ((PRFileDesc*)-1 == poll[pdidx].fd)
+ {
+ /* our vector is full - extend and condition it */
+ poll = (PRPollDesc*)PR_Realloc(
+ poll, (pdidx + 1 + PD_INCR) * sizeof(PRPollDesc));
+ if (NULL == poll) goto out_of_memory;
+ memset(
+ poll + pdidx * sizeof(PRPollDesc),
+ 0, PD_INCR * sizeof(PRPollDesc));
+ poll[pdidx + PD_INCR].fd = (PRFileDesc*)-1;
+ }
+ if ((NULL == poll[pdidx].fd)
+ || (poll[pdidx].fd == set->harray[fsidx]))
+ {
+ /* PR_ASSERT(0 == (poll[pdidx].in_flags & flags)); */
+ /* either empty or prevously defined */
+ poll[pdidx].fd = set->harray[fsidx]; /* possibly redundant */
+ poll[pdidx].in_flags |= flags; /* possibly redundant */
+ break;
+ }
+ }
+ }
+
+#if 0
+ /* Second set the native osfds */
+ for (fsidx = 0; fsidx < set->nsize; fsidx++)
+ {
+ for (pdidx = 0; ((PRFileDesc*)-1 != poll[pdidx].fd); pdidx++)
+ {
+ if ((PRFileDesc*)-1 == poll[pdidx].fd)
+ {
+ /* our vector is full - extend and condition it */
+ poll = PR_Realloc(
+ poll, (pdidx + PD_INCR) * sizeof(PRPollDesc));
+ if (NULL == poll) goto out_of_memory;
+ memset(
+ poll + pdidx * sizeof(PRPollDesc),
+ 0, PD_INCR * sizeof(PRPollDesc));
+ poll[(pdidx + PD_INCR)].fd = (PRFileDesc*)-1;
+ }
+ if ((NULL == poll[pdidx].fd)
+ || (poll[pdidx].fd == set->narray[fsidx]))
+ {
+ /* either empty or prevously defined */
+ poll[pdidx].fd = set->narray[fsidx];
+ PR_ASSERT(0 == (poll[pdidx].in_flags & flags));
+ poll[pdidx].in_flags |= flags;
+ break;
+ }
+ }
+ }
+#endif /* 0 */
+
+ return poll;
+
+out_of_memory:
+ if (NULL != polldesc) PR_DELETE(polldesc);
+ return NULL;
+} /* _pr_setfd */
+
+#endif /* !defined(NEED_SELECT) */
+
+PR_IMPLEMENT(PRInt32) PR_Select(
+ PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr,
+ PR_fd_set *pr_ex, PRIntervalTime timeout)
+{
+
+#if !defined(NEED_SELECT)
+ PRInt32 npds = 0;
+ /*
+ ** Find out how many fds are represented in the three lists.
+ ** Then allocate a polling descriptor for the logical union
+ ** (there can't be any overlapping) and call PR_Poll().
+ */
+
+ PRPollDesc *copy, *poll;
+
+ static PRBool warning = PR_TRUE;
+ if (warning) warning = _PR_Obsolete( "PR_Select()", "PR_Poll()");
+
+ /* try to get an initial guesss at how much space we need */
+ npds = 0;
+ if ((NULL != pr_rd) && ((pr_rd->hsize + pr_rd->nsize - npds) > 0))
+ npds = pr_rd->hsize + pr_rd->nsize;
+ if ((NULL != pr_wr) && ((pr_wr->hsize + pr_wr->nsize - npds) > 0))
+ npds = pr_wr->hsize + pr_wr->nsize;
+ if ((NULL != pr_ex) && ((pr_ex->hsize + pr_ex->nsize - npds) > 0))
+ npds = pr_ex->hsize + pr_ex->nsize;
+
+ if (0 == npds)
+ {
+ PR_Sleep(timeout);
+ return 0;
+ }
+
+ copy = poll = (PRPollDesc*)PR_Calloc(npds + PD_INCR, sizeof(PRPollDesc));
+ if (NULL == poll) goto out_of_memory;
+ poll[npds + PD_INCR - 1].fd = (PRFileDesc*)-1;
+
+ poll = _pr_setfd(pr_rd, PR_POLL_READ, poll);
+ if (NULL == poll) goto out_of_memory;
+ poll = _pr_setfd(pr_wr, PR_POLL_WRITE, poll);
+ if (NULL == poll) goto out_of_memory;
+ poll = _pr_setfd(pr_ex, PR_POLL_EXCEPT, poll);
+ if (NULL == poll) goto out_of_memory;
+ unused = 0;
+ while (NULL != poll[unused].fd && (PRFileDesc*)-1 != poll[unused].fd)
+ {
+ ++unused;
+ }
+
+ PR_ASSERT(unused > 0);
+ npds = PR_Poll(poll, unused, timeout);
+
+ if (npds > 0)
+ {
+ /* Copy the results back into the fd sets */
+ if (NULL != pr_rd) pr_rd->nsize = pr_rd->hsize = 0;
+ if (NULL != pr_wr) pr_wr->nsize = pr_wr->hsize = 0;
+ if (NULL != pr_ex) pr_ex->nsize = pr_ex->hsize = 0;
+ for (copy = &poll[unused - 1]; copy >= poll; --copy)
+ {
+ if (copy->out_flags & PR_POLL_NVAL)
+ {
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
+ npds = -1;
+ break;
+ }
+ if (copy->out_flags & PR_POLL_READ)
+ if (NULL != pr_rd) pr_rd->harray[pr_rd->hsize++] = copy->fd;
+ if (copy->out_flags & PR_POLL_WRITE)
+ if (NULL != pr_wr) pr_wr->harray[pr_wr->hsize++] = copy->fd;
+ if (copy->out_flags & PR_POLL_EXCEPT)
+ if (NULL != pr_ex) pr_ex->harray[pr_ex->hsize++] = copy->fd;
+ }
+ }
+ PR_DELETE(poll);
+
+ return npds;
+out_of_memory:
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ return -1;
+
+#endif /* !defined(NEED_SELECT) */
+
+}