summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcvs2hg <devnull@localhost>2001-10-02 22:21:54 +0000
committercvs2hg <devnull@localhost>2001-10-02 22:21:54 +0000
commit4adbdc39ac7e06fa7f9940c08105b33318f6c747 (patch)
tree0491701fec2e7c3880aea1b7890418adad72b296
parent2c880d4bfb0b36f41b015822e1a2dfccb49aa509 (diff)
downloadnspr-hg-MOZILLA_0_9_5_BRANCH.tar.gz
-rw-r--r--pr/include/md/_solaris.h784
-rw-r--r--pr/include/prlog.h253
-rw-r--r--pr/src/io/prlog.c504
-rw-r--r--pr/src/io/prsocket.c1805
-rw-r--r--pr/src/md/os2/os2io.c798
5 files changed, 4144 insertions, 0 deletions
diff --git a/pr/include/md/_solaris.h b/pr/include/md/_solaris.h
new file mode 100644
index 00000000..fdc2ef64
--- /dev/null
+++ b/pr/include/md/_solaris.h
@@ -0,0 +1,784 @@
+/* -*- 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 nspr_solaris_defs_h___
+#define nspr_solaris_defs_h___
+
+/*
+ * Internal configuration macros
+ */
+
+#define PR_LINKER_ARCH "solaris"
+#define _PR_SI_SYSNAME "SOLARIS"
+#define _PR_SI_ARCHITECTURE "sparc"
+#define PR_DLL_SUFFIX ".so"
+
+#define _PR_VMBASE 0x30000000
+#define _PR_STACK_VMBASE 0x50000000
+#define _MD_DEFAULT_STACK_SIZE (2*65536L)
+#define _MD_MMAP_FLAGS MAP_SHARED
+
+#undef HAVE_STACK_GROWING_UP
+
+#ifndef HAVE_WEAK_IO_SYMBOLS
+#define HAVE_WEAK_IO_SYMBOLS
+#endif
+
+#undef HAVE_WEAK_MALLOC_SYMBOLS
+#define HAVE_DLL
+#define USE_DLFCN
+#define NEED_STRFTIME_LOCK
+
+/*
+ * Intel x86 has atomic instructions.
+ *
+ * Sparc v8 does not have instructions to efficiently implement
+ * atomic increment/decrement operations. In the local threads
+ * only and pthreads versions, we use the default atomic routine
+ * implementation in pratom.c. The obsolete global threads only
+ * version uses a global mutex_t to implement the atomic routines
+ * in solaris.c, which is actually equivalent to the default
+ * implementation.
+ *
+ * 64-bit Solaris requires sparc v9, which has atomic instructions.
+ */
+#if defined(i386) || defined(_PR_GLOBAL_THREADS_ONLY) || defined(IS_64)
+#define _PR_HAVE_ATOMIC_OPS
+#endif
+
+#if defined(_PR_GLOBAL_THREADS_ONLY) || defined(_PR_PTHREADS)
+/*
+ * We have assembly language implementation of atomic
+ * stacks for the 32-bit sparc and x86 architectures only.
+ */
+#if !defined(sparc) || !defined(IS_64)
+#define _PR_HAVE_ATOMIC_CAS
+#endif
+#endif
+
+#define _PR_POLL_AVAILABLE
+#define _PR_USE_POLL
+#define _PR_STAT_HAS_ST_ATIM
+#ifdef SOLARIS2_5
+#define _PR_HAVE_SYSV_SEMAPHORES
+#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY
+#else
+#define _PR_HAVE_POSIX_SEMAPHORES
+#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY
+#endif
+#define _PR_HAVE_GETIPNODEBYNAME
+#define _PR_HAVE_GETIPNODEBYADDR
+#define _PR_INET6_PROBE
+#define _PR_ACCEPT_INHERIT_NONBLOCK
+#ifndef _PR_INET6
+#define AF_INET6 26
+#define AI_V4MAPPED 0x0001
+#define AI_ALL 0x0002
+#define AI_ADDRCONFIG 0x0004
+#define _PR_HAVE_MD_SOCKADDR_IN6
+/* isomorphic to struct in6_addr on Solaris 8 */
+struct _md_in6_addr {
+ union {
+ PRUint8 _S6_u8[16];
+ PRUint32 _S6_u32[4];
+ PRUint32 __S6_align;
+ } _S6_un;
+};
+/* isomorphic to struct sockaddr_in6 on Solaris 8 */
+struct _md_sockaddr_in6 {
+ PRUint16 sin6_family;
+ PRUint16 sin6_port;
+ PRUint32 sin6_flowinfo;
+ struct _md_in6_addr sin6_addr;
+ PRUint32 sin6_scope_id;
+ PRUint32 __sin6_src_id;
+};
+#endif
+#if defined(_PR_GLOBAL_THREADS_ONLY) || defined(_PR_PTHREADS)
+#define _PR_HAVE_GETHOST_R
+#define _PR_HAVE_GETHOST_R_POINTER
+#endif
+
+#include "prinrval.h"
+NSPR_API(PRIntervalTime) _MD_Solaris_GetInterval(void);
+#define _MD_GET_INTERVAL _MD_Solaris_GetInterval
+NSPR_API(PRIntervalTime) _MD_Solaris_TicksPerSecond(void);
+#define _MD_INTERVAL_PER_SEC _MD_Solaris_TicksPerSecond
+
+#if defined(_PR_HAVE_ATOMIC_OPS)
+/*
+** Atomic Operations
+*/
+#define _MD_INIT_ATOMIC()
+
+NSPR_API(PRInt32) _MD_AtomicIncrement(PRInt32 *val);
+#define _MD_ATOMIC_INCREMENT _MD_AtomicIncrement
+
+NSPR_API(PRInt32) _MD_AtomicAdd(PRInt32 *ptr, PRInt32 val);
+#define _MD_ATOMIC_ADD _MD_AtomicAdd
+
+NSPR_API(PRInt32) _MD_AtomicDecrement(PRInt32 *val);
+#define _MD_ATOMIC_DECREMENT _MD_AtomicDecrement
+
+NSPR_API(PRInt32) _MD_AtomicSet(PRInt32 *val, PRInt32 newval);
+#define _MD_ATOMIC_SET _MD_AtomicSet
+#endif /* _PR_HAVE_ATOMIC_OPS */
+
+#if defined(_PR_PTHREADS)
+
+NSPR_API(void) _MD_EarlyInit(void);
+
+#define _MD_EARLY_INIT _MD_EarlyInit
+#define _MD_FINAL_INIT _PR_UnixInit
+
+#elif defined(_PR_GLOBAL_THREADS_ONLY)
+
+#include "prthread.h"
+
+#include <ucontext.h>
+
+/*
+** Iinitialization Related definitions
+*/
+
+NSPR_API(void) _MD_EarlyInit(void);
+
+#define _MD_EARLY_INIT _MD_EarlyInit
+#define _MD_FINAL_INIT _PR_UnixInit
+
+#define _MD_GET_SP(threadp) threadp->md.sp
+
+/*
+** Clean-up the thread machine dependent data structure
+*/
+#define _MD_INIT_THREAD _MD_InitializeThread
+#define _MD_INIT_ATTACHED_THREAD _MD_InitializeThread
+
+NSPR_API(PRStatus) _MD_CreateThread(PRThread *thread,
+ void (*start)(void *),
+ PRThreadPriority priority,
+ PRThreadScope scope,
+ PRThreadState state,
+ PRUint32 stackSize);
+#define _MD_CREATE_THREAD _MD_CreateThread
+
+#define _PR_CONTEXT_TYPE ucontext_t
+
+#define CONTEXT(_thread) (&(_thread)->md.context)
+
+#include <thread.h>
+#include <sys/lwp.h>
+#include <synch.h>
+
+extern struct PRLock *_pr_schedLock;
+
+/*
+** Thread Local Storage
+*/
+
+#define THREAD_KEY_T thread_key_t
+
+extern struct PRThread *_pr_current_thread_tls();
+extern struct _PRCPU *_pr_current_cpu_tls();
+extern struct PRThread *_pr_last_thread_tls();
+
+extern THREAD_KEY_T threadid_key;
+extern THREAD_KEY_T cpuid_key;
+extern THREAD_KEY_T last_thread_key;
+
+#define _MD_CURRENT_THREAD() _pr_current_thread_tls()
+#define _MD_CURRENT_CPU() _pr_current_cpu_tls()
+#define _MD_LAST_THREAD() _pr_last_thread_tls()
+
+#define _MD_SET_CURRENT_THREAD(newval) \
+ PR_BEGIN_MACRO \
+ thr_setspecific(threadid_key, (void *)newval); \
+ PR_END_MACRO
+
+#define _MD_SET_CURRENT_CPU(newval) \
+ PR_BEGIN_MACRO \
+ thr_setspecific(cpuid_key, (void *)newval); \
+ PR_END_MACRO
+
+#define _MD_SET_LAST_THREAD(newval) \
+ PR_BEGIN_MACRO \
+ thr_setspecific(last_thread_key, (void *)newval); \
+ PR_END_MACRO
+
+#define _MD_CLEAN_THREAD(_thread) _MD_cleanup_thread(_thread)
+extern void _MD_exit_thread(PRThread *thread);
+#define _MD_EXIT_THREAD(thread) _MD_exit_thread(thread)
+
+#define _MD_SUSPEND_THREAD(thread) _MD_Suspend(thread)
+#define _MD_RESUME_THREAD(thread) thr_continue((thread)->md.handle)
+
+/* XXXX Needs to be defined - Prashant */
+#define _MD_SUSPEND_CPU(cpu)
+#define _MD_RESUME_CPU(cpu)
+
+extern void _MD_Begin_SuspendAll(void);
+extern void _MD_End_SuspendAll(void);
+extern void _MD_End_ResumeAll(void);
+#define _MD_BEGIN_SUSPEND_ALL() _MD_Begin_SuspendAll()
+#define _MD_BEGIN_RESUME_ALL()
+#define _MD_END_SUSPEND_ALL() _MD_End_SuspendAll()
+#define _MD_END_RESUME_ALL() _MD_End_ResumeAll()
+
+#define _MD_INIT_LOCKS()
+#define _MD_NEW_LOCK(md_lockp) (mutex_init(&((md_lockp)->lock),USYNC_THREAD,NULL) ? PR_FAILURE : PR_SUCCESS)
+#define _MD_FREE_LOCK(md_lockp) mutex_destroy(&((md_lockp)->lock))
+#define _MD_UNLOCK(md_lockp) mutex_unlock(&((md_lockp)->lock))
+#define _MD_TEST_AND_LOCK(md_lockp) mutex_trylock(&((md_lockp)->lock))
+struct _MDLock;
+NSPR_API(void) _MD_lock(struct _MDLock *md_lock);
+#undef PROFILE_LOCKS
+#ifndef PROFILE_LOCKS
+#define _MD_LOCK(md_lockp) _MD_lock(md_lockp)
+#else
+#define _MD_LOCK(md_lockp) \
+ PR_BEGIN_MACRO \
+ int rv = _MD_TEST_AND_LOCK(md_lockp); \
+ if (rv == 0) { \
+ (md_lockp)->hitcount++; \
+ } else { \
+ (md_lockp)->misscount++; \
+ _MD_lock(md_lockp); \
+ } \
+ PR_END_MACRO
+#endif
+
+#define _PR_LOCK_HEAP() if (_pr_heapLock) _MD_LOCK(&_pr_heapLock->md)
+#define _PR_UNLOCK_HEAP() if (_pr_heapLock) _MD_UNLOCK(&_pr_heapLock->md)
+
+#define _MD_ATTACH_THREAD(threadp)
+
+
+#define THR_KEYCREATE thr_keycreate
+#define THR_SELF thr_self
+#define _MD_NEW_CV(condp) cond_init(&((condp)->cv), USYNC_THREAD, 0)
+#define COND_WAIT(condp, mutexp) cond_wait(condp, mutexp)
+#define COND_TIMEDWAIT(condp, mutexp, tspec) \
+ cond_timedwait(condp, mutexp, tspec)
+#define _MD_NOTIFY_CV(condp, lockp) cond_signal(&((condp)->cv))
+#define _MD_NOTIFYALL_CV(condp,unused) cond_broadcast(&((condp)->cv))
+#define _MD_FREE_CV(condp) cond_destroy(&((condp)->cv))
+#define _MD_YIELD() thr_yield()
+#include <time.h>
+/*
+ * Because clock_gettime() on Solaris/x86 2.4 always generates a
+ * segmentation fault, we use an emulated version _pr_solx86_clock_gettime(),
+ * which is implemented using gettimeofday().
+ */
+#if defined(i386) && defined(SOLARIS2_4)
+extern int _pr_solx86_clock_gettime(clockid_t clock_id, struct timespec *tp);
+#define GETTIME(tt) _pr_solx86_clock_gettime(CLOCK_REALTIME, (tt))
+#else
+#define GETTIME(tt) clock_gettime(CLOCK_REALTIME, (tt))
+#endif /* i386 && SOLARIS2_4 */
+
+#define MUTEX_T mutex_t
+#define COND_T cond_t
+
+#define _MD_NEW_SEM(md_semp,_val) sema_init(&((md_semp)->sem),_val,USYNC_THREAD,NULL)
+#define _MD_DESTROY_SEM(md_semp) sema_destroy(&((md_semp)->sem))
+#define _MD_WAIT_SEM(md_semp) sema_wait(&((md_semp)->sem))
+#define _MD_POST_SEM(md_semp) sema_post(&((md_semp)->sem))
+
+#define _MD_SAVE_ERRNO(_thread)
+#define _MD_RESTORE_ERRNO(_thread)
+#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu)
+
+extern struct _MDLock _pr_ioq_lock;
+#define _MD_IOQ_LOCK() _MD_LOCK(&_pr_ioq_lock)
+#define _MD_IOQ_UNLOCK() _MD_UNLOCK(&_pr_ioq_lock)
+
+extern PRStatus _MD_wait(struct PRThread *, PRIntervalTime timeout);
+#define _MD_WAIT _MD_wait
+
+extern PRStatus _MD_WakeupWaiter(struct PRThread *);
+#define _MD_WAKEUP_WAITER _MD_WakeupWaiter
+
+NSPR_API(void) _MD_InitIO(void);
+#define _MD_INIT_IO _MD_InitIO
+
+#define _MD_INIT_CONTEXT(_thread, _sp, _main, status)
+#define _MD_SWITCH_CONTEXT(_thread)
+#define _MD_RESTORE_CONTEXT(_newThread)
+
+struct _MDLock {
+ MUTEX_T lock;
+#ifdef PROFILE_LOCKS
+ PRInt32 hitcount;
+ PRInt32 misscount;
+#endif
+};
+
+struct _MDCVar {
+ COND_T cv;
+};
+
+struct _MDSemaphore {
+ sema_t sem;
+};
+
+struct _MDThread {
+ _PR_CONTEXT_TYPE context;
+ thread_t handle;
+ lwpid_t lwpid;
+ uint_t sp; /* stack pointer */
+ uint_t threadID; /* ptr to solaris-internal thread id structures */
+ struct _MDSemaphore waiter_sem;
+};
+
+struct _MDThreadStack {
+ PRInt8 notused;
+};
+
+struct _MDSegment {
+ PRInt8 notused;
+};
+
+/*
+ * md-specific cpu structure field, common to all Unix platforms
+ */
+#define _PR_MD_MAX_OSFD FD_SETSIZE
+
+struct _MDCPU_Unix {
+ PRCList ioQ;
+ PRUint32 ioq_timeout;
+ PRInt32 ioq_max_osfd;
+ PRInt32 ioq_osfd_cnt;
+#ifndef _PR_USE_POLL
+ fd_set fd_read_set, fd_write_set, fd_exception_set;
+ PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD],
+ fd_exception_cnt[_PR_MD_MAX_OSFD];
+#else
+ struct pollfd *ioq_pollfds;
+ int ioq_pollfds_size;
+#endif /* _PR_USE_POLL */
+};
+
+#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ)
+#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu))
+#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set)
+#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt)
+#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set)
+#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt)
+#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set)
+#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt)
+#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout)
+#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd)
+#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt)
+#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds)
+#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size)
+
+#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32
+
+
+struct _MDCPU {
+ struct _MDCPU_Unix md_unix;
+};
+
+/* The following defines the unwrapped versions of select() and poll(). */
+extern int _select(int nfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout);
+#define _MD_SELECT _select
+
+#include <poll.h>
+#define _MD_POLL _poll
+extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout);
+
+PR_BEGIN_EXTERN_C
+
+/*
+** Missing function prototypes
+*/
+extern int gethostname (char *name, int namelen);
+
+PR_END_EXTERN_C
+
+#else /* _PR_GLOBAL_THREADS_ONLY */
+
+/*
+ * LOCAL_THREADS_ONLY implementation on Solaris
+ */
+
+#include "prthread.h"
+
+#include <errno.h>
+#include <ucontext.h>
+#include <sys/stack.h>
+#include <synch.h>
+
+/*
+** Iinitialization Related definitions
+*/
+
+NSPR_API(void) _MD_EarlyInit(void);
+NSPR_API(void) _MD_SolarisInit();
+#define _MD_EARLY_INIT _MD_EarlyInit
+#define _MD_FINAL_INIT _MD_SolarisInit
+#define _MD_INIT_THREAD _MD_InitializeThread
+
+#ifdef USE_SETJMP
+
+#include <setjmp.h>
+
+#define _PR_CONTEXT_TYPE jmp_buf
+
+#ifdef sparc
+#define _MD_GET_SP(_t) (_t)->md.context[2]
+#else
+#define _MD_GET_SP(_t) (_t)->md.context[4]
+#endif
+
+#define PR_NUM_GCREGS _JBLEN
+#define CONTEXT(_thread) (_thread)->md.context
+
+#else /* ! USE_SETJMP */
+
+#ifdef sparc
+#define _PR_CONTEXT_TYPE ucontext_t
+#define _MD_GET_SP(_t) (_t)->md.context.uc_mcontext.gregs[REG_SP]
+/*
+** Sparc's use register windows. the _MD_GetRegisters for the sparc's
+** doesn't actually store anything into the argument buffer; instead the
+** register windows are homed to the stack. I assume that the stack
+** always has room for the registers to spill to...
+*/
+#define PR_NUM_GCREGS 0
+#else
+#define _PR_CONTEXT_TYPE unsigned int edi; sigset_t oldMask, blockMask; ucontext_t
+#define _MD_GET_SP(_t) (_t)->md.context.uc_mcontext.gregs[USP]
+#define PR_NUM_GCREGS _JBLEN
+#endif
+
+#define CONTEXT(_thread) (&(_thread)->md.context)
+
+#endif /* ! USE_SETJMP */
+
+#include <time.h>
+/*
+ * Because clock_gettime() on Solaris/x86 always generates a
+ * segmentation fault, we use an emulated version _pr_solx86_clock_gettime(),
+ * which is implemented using gettimeofday().
+ */
+#ifdef i386
+#define GETTIME(tt) _pr_solx86_clock_gettime(CLOCK_REALTIME, (tt))
+#else
+#define GETTIME(tt) clock_gettime(CLOCK_REALTIME, (tt))
+#endif /* i386 */
+
+#define _MD_SAVE_ERRNO(_thread) (_thread)->md.errcode = errno;
+#define _MD_RESTORE_ERRNO(_thread) errno = (_thread)->md.errcode;
+
+#ifdef sparc
+
+#ifdef USE_SETJMP
+#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \
+ PR_BEGIN_MACRO \
+ int *context = (_thread)->md.context; \
+ *status = PR_TRUE; \
+ (void) setjmp(context); \
+ (_thread)->md.context[1] = (int) ((_sp) - 64); \
+ (_thread)->md.context[2] = (int) _main; \
+ (_thread)->md.context[3] = (int) _main + 4; \
+ _thread->no_sched = 0; \
+ PR_END_MACRO
+
+#define _MD_SWITCH_CONTEXT(_thread) \
+ if (!setjmp(CONTEXT(_thread))) { \
+ _MD_SAVE_ERRNO(_thread) \
+ _MD_SET_LAST_THREAD(_thread); \
+ _MD_SET_CURRENT_THREAD(_thread); \
+ _PR_Schedule(); \
+ }
+
+#define _MD_RESTORE_CONTEXT(_newThread) \
+{ \
+ _MD_RESTORE_ERRNO(_newThread) \
+ _MD_SET_CURRENT_THREAD(_newThread); \
+ longjmp(CONTEXT(_newThread), 1); \
+}
+
+#else
+/*
+** Initialize the thread context preparing it to execute _main.
+*/
+#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \
+ PR_BEGIN_MACRO \
+ ucontext_t *uc = CONTEXT(_thread); \
+ *status = PR_TRUE; \
+ getcontext(uc); \
+ uc->uc_stack.ss_sp = (char *) ((unsigned long)(_sp - WINDOWSIZE - SA(MINFRAME)) & 0xfffffff8); \
+ uc->uc_stack.ss_size = _thread->stack->stackSize; \
+ uc->uc_stack.ss_flags = 0; /* ? */ \
+ uc->uc_mcontext.gregs[REG_SP] = (unsigned int) uc->uc_stack.ss_sp; \
+ uc->uc_mcontext.gregs[REG_PC] = (unsigned int) _main; \
+ uc->uc_mcontext.gregs[REG_nPC] = (unsigned int) ((char*)_main)+4; \
+ uc->uc_flags = UC_ALL; \
+ _thread->no_sched = 0; \
+ PR_END_MACRO
+
+/*
+** Switch away from the current thread context by saving its state and
+** calling the thread scheduler. Reload cpu when we come back from the
+** context switch because it might have changed.
+*/
+#define _MD_SWITCH_CONTEXT(_thread) \
+ PR_BEGIN_MACRO \
+ if (!getcontext(CONTEXT(_thread))) { \
+ _MD_SAVE_ERRNO(_thread); \
+ _MD_SET_LAST_THREAD(_thread); \
+ _PR_Schedule(); \
+ } \
+ PR_END_MACRO
+
+/*
+** Restore a thread context that was saved by _MD_SWITCH_CONTEXT or
+** initialized by _MD_INIT_CONTEXT.
+*/
+#define _MD_RESTORE_CONTEXT(_newThread) \
+ PR_BEGIN_MACRO \
+ ucontext_t *uc = CONTEXT(_newThread); \
+ uc->uc_mcontext.gregs[11] = 1; \
+ _MD_RESTORE_ERRNO(_newThread); \
+ _MD_SET_CURRENT_THREAD(_newThread); \
+ setcontext(uc); \
+ PR_END_MACRO
+#endif
+
+#else /* x86 solaris */
+
+#ifdef USE_SETJMP
+
+#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \
+ PR_BEGIN_MACRO \
+ *status = PR_TRUE; \
+ if (setjmp(CONTEXT(_thread))) _main(); \
+ _MD_GET_SP(_thread) = (int) ((_sp) - 64); \
+ PR_END_MACRO
+
+#define _MD_SWITCH_CONTEXT(_thread) \
+ if (!setjmp(CONTEXT(_thread))) { \
+ _MD_SAVE_ERRNO(_thread) \
+ _PR_Schedule(); \
+ }
+
+#define _MD_RESTORE_CONTEXT(_newThread) \
+{ \
+ _MD_RESTORE_ERRNO(_newThread) \
+ _MD_SET_CURRENT_THREAD(_newThread); \
+ longjmp(CONTEXT(_newThread), 1); \
+}
+
+#else /* USE_SETJMP */
+
+#define WINDOWSIZE 0
+
+int getedi(void);
+void setedi(int);
+
+#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \
+ PR_BEGIN_MACRO \
+ ucontext_t *uc = CONTEXT(_thread); \
+ *status = PR_TRUE; \
+ getcontext(uc); \
+ /* Force sp to be double aligned! */ \
+ uc->uc_mcontext.gregs[USP] = (int) ((unsigned long)(_sp - WINDOWSIZE - SA(MINFRAME)) & 0xfffffff8); \
+ uc->uc_mcontext.gregs[PC] = (int) _main; \
+ (_thread)->no_sched = 0; \
+ PR_END_MACRO
+
+/* getcontext() may return 1, contrary to what the man page says */
+#define _MD_SWITCH_CONTEXT(_thread) \
+ PR_BEGIN_MACRO \
+ ucontext_t *uc = CONTEXT(_thread); \
+ PR_ASSERT(_thread->no_sched); \
+ sigfillset(&((_thread)->md.blockMask)); \
+ sigprocmask(SIG_BLOCK, &((_thread)->md.blockMask), \
+ &((_thread)->md.oldMask)); \
+ (_thread)->md.edi = getedi(); \
+ if (! getcontext(uc)) { \
+ sigprocmask(SIG_SETMASK, &((_thread)->md.oldMask), NULL); \
+ uc->uc_mcontext.gregs[EDI] = (_thread)->md.edi; \
+ _MD_SAVE_ERRNO(_thread) \
+ _MD_SET_LAST_THREAD(_thread); \
+ _PR_Schedule(); \
+ } else { \
+ sigprocmask(SIG_SETMASK, &((_thread)->md.oldMask), NULL); \
+ setedi((_thread)->md.edi); \
+ PR_ASSERT(_MD_LAST_THREAD() !=_MD_CURRENT_THREAD()); \
+ _MD_LAST_THREAD()->no_sched = 0; \
+ } \
+ PR_END_MACRO
+
+/*
+** Restore a thread context, saved by _PR_SWITCH_CONTEXT
+*/
+#define _MD_RESTORE_CONTEXT(_newthread) \
+ PR_BEGIN_MACRO \
+ ucontext_t *uc = CONTEXT(_newthread); \
+ uc->uc_mcontext.gregs[EAX] = 1; \
+ _MD_RESTORE_ERRNO(_newthread) \
+ _MD_SET_CURRENT_THREAD(_newthread); \
+ (_newthread)->no_sched = 1; \
+ setcontext(uc); \
+ PR_END_MACRO
+#endif /* USE_SETJMP */
+
+#endif /* sparc */
+
+struct _MDLock {
+ PRInt8 notused;
+};
+
+struct _MDCVar {
+ PRInt8 notused;
+};
+
+struct _MDSemaphore {
+ PRInt8 notused;
+};
+
+struct _MDThread {
+ _PR_CONTEXT_TYPE context;
+ int errcode;
+ int id;
+};
+
+struct _MDThreadStack {
+ PRInt8 notused;
+};
+
+struct _MDSegment {
+ PRInt8 notused;
+};
+
+/*
+ * md-specific cpu structure field
+ */
+#define _PR_MD_MAX_OSFD FD_SETSIZE
+
+struct _MDCPU_Unix {
+ PRCList ioQ;
+ PRUint32 ioq_timeout;
+ PRInt32 ioq_max_osfd;
+ PRInt32 ioq_osfd_cnt;
+#ifndef _PR_USE_POLL
+ fd_set fd_read_set, fd_write_set, fd_exception_set;
+ PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD],
+ fd_exception_cnt[_PR_MD_MAX_OSFD];
+#else
+ struct pollfd *ioq_pollfds;
+ int ioq_pollfds_size;
+#endif /* _PR_USE_POLL */
+};
+
+#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ)
+#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu))
+#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set)
+#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt)
+#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set)
+#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt)
+#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set)
+#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt)
+#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout)
+#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd)
+#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt)
+#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds)
+#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size)
+
+#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32
+
+struct _MDCPU {
+ struct _MDCPU_Unix md_unix;
+};
+
+#ifndef _PR_PTHREADS
+#define _MD_INIT_LOCKS()
+#endif
+#define _MD_NEW_LOCK(lock) PR_SUCCESS
+#define _MD_FREE_LOCK(lock)
+#define _MD_LOCK(lock)
+#define _MD_UNLOCK(lock)
+#define _MD_INIT_IO()
+#define _MD_IOQ_LOCK()
+#define _MD_IOQ_UNLOCK()
+
+#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu)
+#define _MD_INIT_THREAD _MD_InitializeThread
+#define _MD_EXIT_THREAD(thread)
+#define _MD_SUSPEND_THREAD(thread)
+#define _MD_RESUME_THREAD(thread)
+#define _MD_CLEAN_THREAD(_thread)
+
+extern PRStatus _MD_WAIT(struct PRThread *, PRIntervalTime timeout);
+extern PRStatus _MD_WAKEUP_WAITER(struct PRThread *);
+extern void _MD_YIELD(void);
+extern PRStatus _MD_InitializeThread(PRThread *thread);
+extern void _MD_SET_PRIORITY(struct _MDThread *thread,
+ PRThreadPriority newPri);
+extern PRStatus _MD_CREATE_THREAD(PRThread *thread, void (*start) (void *),
+ PRThreadPriority priority, PRThreadScope scope, PRThreadState state,
+ PRUint32 stackSize);
+
+NSPR_API(PRIntervalTime) _MD_Solaris_GetInterval(void);
+#define _MD_GET_INTERVAL _MD_Solaris_GetInterval
+NSPR_API(PRIntervalTime) _MD_Solaris_TicksPerSecond(void);
+#define _MD_INTERVAL_PER_SEC _MD_Solaris_TicksPerSecond
+
+/* The following defines the unwrapped versions of select() and poll(). */
+extern int _select(int nfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout);
+#define _MD_SELECT _select
+
+#include <stropts.h>
+#include <poll.h>
+#define _MD_POLL _poll
+extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout);
+
+PR_BEGIN_EXTERN_C
+
+/*
+** Missing function prototypes
+*/
+extern int gethostname (char *name, int namelen);
+
+PR_END_EXTERN_C
+
+#endif /* _PR_GLOBAL_THREADS_ONLY */
+
+#endif /* nspr_solaris_defs_h___ */
+
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) */
+
+}
diff --git a/pr/src/md/os2/os2io.c b/pr/src/md/os2/os2io.c
new file mode 100644
index 00000000..926d6e10
--- /dev/null
+++ b/pr/src/md/os2/os2io.c
@@ -0,0 +1,798 @@
+/* -*- 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.
+ */
+
+
+/*
+ * 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
+ * 03/23/2000 IBM Corp. Changed write() to DosWrite(). EMX i/o
+ * calls cannot be intermixed with DosXXX
+ * calls since EMX remaps file/socket
+ * handles.
+ * 04/27/2000 IBM Corp. Changed open file to be more like NT and
+ * better handle PR_TRUNCATE | PR_CREATE_FILE
+ * and also fixed _PR_MD_SET_FD_INHERITABLE
+ */
+
+/* OS2 IO module
+ *
+ * Assumes synchronous I/O.
+ *
+ */
+
+#include "primpl.h"
+#include "prio.h"
+#include <ctype.h>
+#ifdef XP_OS2_VACPP
+#include <direct.h>
+#else
+#include <limits.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <io.h>
+#endif
+
+struct _MDLock _pr_ioq_lock;
+
+PRStatus
+_PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks)
+{
+ PRInt32 rv;
+ ULONG count;
+
+ PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
+ SEM_INDEFINITE_WAIT : PR_IntervalToMilliseconds(ticks);
+ rv = DosWaitEventSem(thread->md.blocked_sema.sem, msecs);
+ DosResetEventSem(thread->md.blocked_sema.sem, &count);
+ switch(rv)
+ {
+ case NO_ERROR:
+ return PR_SUCCESS;
+ break;
+ case ERROR_TIMEOUT:
+ _PR_THREAD_LOCK(thread);
+ if (thread->state == _PR_IO_WAIT) {
+ ;
+ } else {
+ if (thread->wait.cvar != NULL) {
+ thread->wait.cvar = NULL;
+ _PR_THREAD_UNLOCK(thread);
+ } else {
+ /* The CVAR was notified just as the timeout
+ * occurred. This led to us being notified twice.
+ * call SemRequest() to clear the semaphore.
+ */
+ _PR_THREAD_UNLOCK(thread);
+ rv = DosWaitEventSem(thread->md.blocked_sema.sem, 0);
+ DosResetEventSem(thread->md.blocked_sema.sem, &count);
+ PR_ASSERT(rv == NO_ERROR);
+ }
+ }
+ return PR_SUCCESS;
+ break;
+ default:
+ break;
+ }
+ return PR_FAILURE;
+}
+PRStatus
+_PR_MD_WAKEUP_WAITER(PRThread *thread)
+{
+ if ( _PR_IS_NATIVE_THREAD(thread) )
+ {
+ if (DosPostEventSem(thread->md.blocked_sema.sem) != NO_ERROR)
+ return PR_FAILURE;
+ else
+ return PR_SUCCESS;
+ }
+}
+
+
+/* --- FILE IO ----------------------------------------------------------- */
+/*
+ * _PR_MD_OPEN() -- Open a file
+ *
+ * returns: a fileHandle
+ *
+ * The NSPR open flags (osflags) are translated into flags for OS/2
+ *
+ * Mode seems to be passed in as a unix style file permissions argument
+ * as in 0666, in the case of opening the logFile.
+ *
+ */
+PRInt32
+_PR_MD_OPEN(const char *name, PRIntn osflags, int mode)
+{
+ HFILE file;
+ PRInt32 access = OPEN_SHARE_DENYNONE;
+ PRInt32 flags = 0L;
+ PRInt32 rc;
+ PRUword actionTaken;
+
+ ULONG CurMaxFH = 0;
+ LONG ReqCount = 1;
+ ULONG fattr;
+
+ if (osflags & PR_SYNC) access |= OPEN_FLAGS_WRITE_THROUGH;
+
+ if (osflags & PR_RDONLY)
+ access |= OPEN_ACCESS_READONLY;
+ else if (osflags & PR_WRONLY)
+ access |= OPEN_ACCESS_WRITEONLY;
+ else if(osflags & PR_RDWR)
+ access |= OPEN_ACCESS_READWRITE;
+
+ if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL )
+ {
+ flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_FAIL_IF_EXISTS;
+ }
+ else if (osflags & PR_CREATE_FILE)
+ {
+ if (osflags & PR_TRUNCATE)
+ flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS;
+ else
+ flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
+ }
+ else
+ {
+ if (osflags & PR_TRUNCATE)
+ flags = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS;
+ else
+ flags = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
+ }
+
+ if (isxdigit(mode) == 0) /* file attribs are hex, UNIX modes octal */
+ fattr = ((ULONG)mode == FILE_HIDDEN) ? FILE_HIDDEN : FILE_NORMAL;
+ else fattr = FILE_NORMAL;
+
+ /* OS/2 sets the Max file handles per process to 20 by default */
+ DosSetRelMaxFH(&ReqCount, &CurMaxFH);
+
+ rc = DosOpen((char*)name,
+ &file, /* file handle if successful */
+ &actionTaken, /* reason for failure */
+ 0, /* initial size of new file */
+ fattr, /* file system attributes */
+ flags, /* Open flags */
+ access, /* Open mode and rights */
+ 0); /* OS/2 Extended Attributes */
+ if (rc != NO_ERROR) {
+ _PR_MD_MAP_OPEN_ERROR(rc);
+ return -1;
+ }
+
+ return (PRInt32)file;
+}
+
+PRInt32
+_PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len)
+{
+ ULONG bytes;
+ int rv;
+
+ rv = DosRead((HFILE)fd->secret->md.osfd,
+ (PVOID)buf,
+ len,
+ &bytes);
+
+ if (rv != NO_ERROR)
+ {
+ /* ERROR_HANDLE_EOF can only be returned by async io */
+ PR_ASSERT(rv != ERROR_HANDLE_EOF);
+ if (rv == ERROR_BROKEN_PIPE)
+ return 0;
+ else {
+ _PR_MD_MAP_READ_ERROR(rv);
+ return -1;
+ }
+ }
+ return (PRInt32)bytes;
+}
+
+PRInt32
+_PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len)
+{
+ PRInt32 bytes;
+ int rv;
+
+ rv = DosWrite((HFILE)fd->secret->md.osfd,
+ (PVOID)buf,
+ len,
+ (PULONG)&bytes);
+
+ if (rv != NO_ERROR)
+ {
+ _PR_MD_MAP_WRITE_ERROR(rv);
+ return -1;
+ }
+
+ return bytes;
+} /* --- end _PR_MD_WRITE() --- */
+
+PRInt32
+_PR_MD_LSEEK(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence)
+{
+ PRInt32 rv;
+ PRUword newLocation;
+
+ rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, offset, whence, &newLocation);
+
+ if (rv != NO_ERROR) {
+ _PR_MD_MAP_LSEEK_ERROR(rv);
+ return -1;
+ } else
+ return newLocation;
+}
+
+PRInt64
+_PR_MD_LSEEK64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence)
+{
+#ifdef NO_LONG_LONG
+ PRInt64 result;
+ PRInt32 rv, low = offset.lo, hi = offset.hi;
+ PRUword newLocation;
+
+ rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, low, whence, &newLocation);
+ rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, hi, FILE_CURRENT, &newLocation);
+
+ if (rv != NO_ERROR) {
+ _PR_MD_MAP_LSEEK_ERROR(rv);
+ hi = newLocation = -1;
+ }
+
+ result.lo = newLocation;
+ result.hi = hi;
+ return result;
+
+#else
+ PRInt32 where, rc, lo = (PRInt32)offset, hi = (PRInt32)(offset >> 32);
+ PRUint64 rv;
+ PRUint32 newLocation, uhi;
+
+ switch (whence)
+ {
+ case PR_SEEK_SET:
+ where = FILE_BEGIN;
+ break;
+ case PR_SEEK_CUR:
+ where = FILE_CURRENT;
+ break;
+ case PR_SEEK_END:
+ where = FILE_END;
+ break;
+ default:
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return -1;
+}
+
+ rc = DosSetFilePtr((HFILE)fd->secret->md.osfd, lo, where, (PULONG)&newLocation);
+
+ if (rc != NO_ERROR) {
+ _PR_MD_MAP_LSEEK_ERROR(rc);
+ return -1;
+ }
+
+ uhi = (PRUint32)hi;
+ PR_ASSERT((PRInt32)uhi >= 0);
+ rv = uhi;
+ PR_ASSERT((PRInt64)rv >= 0);
+ rv = (rv << 32);
+ PR_ASSERT((PRInt64)rv >= 0);
+ rv += newLocation;
+ PR_ASSERT((PRInt64)rv >= 0);
+ return (PRInt64)rv;
+#endif
+}
+
+PRInt32
+_PR_MD_FSYNC(PRFileDesc *fd)
+{
+ PRInt32 rc = DosResetBuffer((HFILE)fd->secret->md.osfd);
+
+ if (rc != NO_ERROR) {
+ if (rc != ERROR_ACCESS_DENIED) {
+ _PR_MD_MAP_FSYNC_ERROR(rc);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+PRInt32
+_MD_CloseFile(PRInt32 osfd)
+{
+ PRInt32 rv;
+
+ rv = DosClose((HFILE)osfd);
+ if (rv != NO_ERROR)
+ _PR_MD_MAP_CLOSE_ERROR(rv);
+ return rv;
+}
+
+
+/* --- DIR IO ------------------------------------------------------------ */
+#define GetFileFromDIR(d) (d)->d_entry.achName
+#define GetFileAttr(d) (d)->d_entry.attrFile
+
+void FlipSlashes(char *cp, int len)
+{
+ while (--len >= 0) {
+ if (cp[0] == '/') {
+ cp[0] = PR_DIRECTORY_SEPARATOR;
+ }
+ cp++;
+ }
+}
+
+/*
+**
+** Local implementations of standard Unix RTL functions which are not provided
+** by the VAC RTL.
+**
+*/
+
+PRInt32
+_PR_MD_CLOSE_DIR(_MDDir *d)
+{
+ PRInt32 rc;
+
+ if ( d ) {
+ rc = DosFindClose(d->d_hdl);
+ if(rc == NO_ERROR){
+ d->magic = (PRUint32)-1;
+ return PR_SUCCESS;
+ } else {
+ _PR_MD_MAP_CLOSEDIR_ERROR(rc);
+ return PR_FAILURE;
+ }
+ }
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return PR_FAILURE;
+}
+
+
+PRStatus
+_PR_MD_OPEN_DIR(_MDDir *d, const char *name)
+{
+ char filename[ CCHMAXPATH ];
+ PRUword numEntries, rc;
+
+ numEntries = 1;
+
+ PR_snprintf(filename, CCHMAXPATH, "%s%s%s",
+ name, PR_DIRECTORY_SEPARATOR_STR, "*.*");
+ FlipSlashes( filename, strlen(filename) );
+
+ d->d_hdl = HDIR_CREATE;
+
+ rc = DosFindFirst( filename,
+ &d->d_hdl,
+ FILE_DIRECTORY | FILE_HIDDEN,
+ &(d->d_entry),
+ sizeof(d->d_entry),
+ &numEntries,
+ FIL_STANDARD);
+ if ( rc != NO_ERROR ) {
+ _PR_MD_MAP_OPENDIR_ERROR(rc);
+ return PR_FAILURE;
+ }
+ d->firstEntry = PR_TRUE;
+ d->magic = _MD_MAGIC_DIR;
+ return PR_SUCCESS;
+}
+
+char *
+_PR_MD_READ_DIR(_MDDir *d, PRIntn flags)
+{
+ PRUword numFiles = 1;
+ BOOL rv;
+ char *fileName;
+ USHORT fileAttr;
+
+ if ( d ) {
+ while (1) {
+ if (d->firstEntry) {
+ d->firstEntry = PR_FALSE;
+ rv = NO_ERROR;
+ } else {
+ rv = DosFindNext(d->d_hdl,
+ &(d->d_entry),
+ sizeof(d->d_entry),
+ &numFiles);
+ }
+ if (rv != NO_ERROR) {
+ break;
+ }
+ fileName = GetFileFromDIR(d);
+ fileAttr = GetFileAttr(d);
+ if ( (flags & PR_SKIP_DOT) &&
+ (fileName[0] == '.') && (fileName[1] == '\0'))
+ continue;
+ if ( (flags & PR_SKIP_DOT_DOT) &&
+ (fileName[0] == '.') && (fileName[1] == '.') &&
+ (fileName[2] == '\0'))
+ continue;
+ /*
+ * XXX
+ * Is this the correct definition of a hidden file on OS/2?
+ */
+ if ((flags & PR_SKIP_NONE) && (fileAttr & FILE_HIDDEN))
+ return fileName;
+ else if ((flags & PR_SKIP_HIDDEN) && (fileAttr & FILE_HIDDEN))
+ continue;
+ return fileName;
+ }
+ PR_ASSERT(NO_ERROR != rv);
+ _PR_MD_MAP_READDIR_ERROR(rv);
+ return NULL;
+ }
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return NULL;
+}
+
+PRInt32
+_PR_MD_DELETE(const char *name)
+{
+ PRInt32 rc = DosDelete((char*)name);
+ if(rc == NO_ERROR) {
+ return 0;
+ } else {
+ _PR_MD_MAP_DELETE_ERROR(rc);
+ return -1;
+ }
+}
+
+PRInt32
+_PR_MD_STAT(const char *fn, struct stat *info)
+{
+ PRInt32 rv;
+ char filename[CCHMAXPATH];
+
+ PR_snprintf(filename, CCHMAXPATH, "%s", fn);
+ FlipSlashes(filename, strlen(filename));
+
+ rv = _stat((char*)filename, info);
+ if (-1 == rv) {
+ /*
+ * Check for MSVC runtime library _stat() bug.
+ * (It's really a bug in FindFirstFile().)
+ * If a pathname ends in a backslash or slash,
+ * e.g., c:\temp\ or c:/temp/, _stat() will fail.
+ * Note: a pathname ending in a slash (e.g., c:/temp/)
+ * can be handled by _stat() on NT but not on Win95.
+ *
+ * We remove the backslash or slash at the end and
+ * try again.
+ *
+ * Not sure if this happens on OS/2 or not,
+ * but it doesn't hurt to be careful.
+ */
+
+ int len = strlen(fn);
+ if (len > 0 && len <= _MAX_PATH
+ && (fn[len - 1] == '\\' || fn[len - 1] == '/')) {
+ char newfn[_MAX_PATH + 1];
+
+ strcpy(newfn, fn);
+ newfn[len - 1] = '\0';
+ rv = _stat(newfn, info);
+ }
+ }
+
+ if (-1 == rv) {
+ _PR_MD_MAP_STAT_ERROR(errno);
+ }
+ return rv;
+}
+
+PRInt32
+_PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info)
+{
+ struct stat sb;
+ PRInt32 rv;
+ PRInt64 s, s2us;
+
+ if ( (rv = _PR_MD_STAT(fn, &sb)) == 0 ) {
+ if (info) {
+ if (S_IFREG & sb.st_mode)
+ info->type = PR_FILE_FILE ;
+ else if (S_IFDIR & sb.st_mode)
+ info->type = PR_FILE_DIRECTORY;
+ else
+ info->type = PR_FILE_OTHER;
+ info->size = sb.st_size;
+ LL_I2L(s2us, PR_USEC_PER_SEC);
+ LL_I2L(s, sb.st_mtime);
+ LL_MUL(s, s, s2us);
+ info->modifyTime = s;
+ LL_I2L(s, sb.st_ctime);
+ LL_MUL(s, s, s2us);
+ info->creationTime = s;
+ }
+ }
+ return rv;
+}
+
+PRInt32
+_PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info)
+{
+ PRFileInfo info32;
+ PRInt32 rv = _PR_MD_GETFILEINFO(fn, &info32);
+ if (0 == rv)
+ {
+ info->type = info32.type;
+ LL_UI2L(info->size,info32.size);
+ info->modifyTime = info32.modifyTime;
+ info->creationTime = info32.creationTime;
+ }
+ return rv;
+}
+
+PRInt32
+_PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info)
+{
+ /* For once, the VAC compiler/library did a nice thing.
+ * The file handle used by the C runtime is the same one
+ * returned by the OS when you call DosOpen(). This means
+ * that you can take an OS HFILE and use it with C file
+ * functions. The only caveat is that you have to call
+ * _setmode() first to initialize some junk. This is
+ * immensely useful because I did not have a clue how to
+ * implement this function otherwise. The windows folks
+ * took the source from the Microsoft C library source, but
+ * IBM wasn't kind enough to ship the source with VAC.
+ * On second thought, the needed function could probably
+ * be gotten from the OS/2 GNU library source, but the
+ * point is now moot.
+ */
+ struct stat hinfo;
+ PRInt64 s, s2us;
+
+ _setmode(fd->secret->md.osfd, O_BINARY);
+ if(fstat((int)fd->secret->md.osfd, &hinfo) != NO_ERROR) {
+ _PR_MD_MAP_FSTAT_ERROR(errno);
+ return -1;
+ }
+
+ if (hinfo.st_mode & S_IFDIR)
+ info->type = PR_FILE_DIRECTORY;
+ else
+ info->type = PR_FILE_FILE;
+
+ info->size = hinfo.st_size;
+ LL_I2L(s2us, PR_USEC_PER_SEC);
+ LL_I2L(s, hinfo.st_mtime);
+ LL_MUL(s, s, s2us);
+ info->modifyTime = s;
+ LL_I2L(s, hinfo.st_ctime);
+ LL_MUL(s, s, s2us);
+ info->creationTime = s;
+
+ return 0;
+}
+
+PRInt32
+_PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info)
+{
+ PRFileInfo info32;
+ PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, &info32);
+ if (0 == rv)
+ {
+ info->type = info32.type;
+ LL_UI2L(info->size,info32.size);
+
+ info->modifyTime = info32.modifyTime;
+ info->creationTime = info32.creationTime;
+ }
+ return rv;
+}
+
+
+PRInt32
+_PR_MD_RENAME(const char *from, const char *to)
+{
+ PRInt32 rc;
+ /* Does this work with dot-relative pathnames? */
+ if ( (rc = DosMove((char *)from, (char *)to)) == NO_ERROR) {
+ return 0;
+ } else {
+ _PR_MD_MAP_RENAME_ERROR(rc);
+ return -1;
+ }
+}
+
+PRInt32
+_PR_MD_ACCESS(const char *name, PRAccessHow how)
+{
+ PRInt32 rv;
+ switch (how) {
+ case PR_ACCESS_WRITE_OK:
+ rv = access(name, 02);
+ break;
+ case PR_ACCESS_READ_OK:
+ rv = access(name, 04);
+ break;
+ case PR_ACCESS_EXISTS:
+ return access(name, 00);
+ break;
+ default:
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return -1;
+ }
+ if (rv < 0)
+ _PR_MD_MAP_ACCESS_ERROR(errno);
+ return rv;
+}
+
+PRInt32
+_PR_MD_MKDIR(const char *name, PRIntn mode)
+{
+ PRInt32 rc;
+ /* XXXMB - how to translate the "mode"??? */
+ if ((rc = DosCreateDir((char *)name, NULL))== NO_ERROR) {
+ return 0;
+ } else {
+ _PR_MD_MAP_MKDIR_ERROR(rc);
+ return -1;
+ }
+}
+
+PRInt32
+_PR_MD_RMDIR(const char *name)
+{
+ PRInt32 rc;
+ if ( (rc = DosDeleteDir((char *)name)) == NO_ERROR) {
+ return 0;
+ } else {
+ _PR_MD_MAP_RMDIR_ERROR(rc);
+ return -1;
+ }
+}
+
+PRStatus
+_PR_MD_LOCKFILE(PRInt32 f)
+{
+ PRInt32 rv;
+ FILELOCK lock, unlock;
+
+ lock.lOffset = 0;
+ lock.lRange = 0xffffffff;
+ unlock.lOffset = 0;
+ unlock.lRange = 0;
+
+ /*
+ * loop trying to DosSetFileLocks(),
+ * pause for a few miliseconds when can't get the lock
+ * and try again
+ */
+ for( rv = FALSE; rv == FALSE; /* do nothing */ )
+ {
+
+ rv = DosSetFileLocks( (HFILE) f,
+ &unlock, &lock,
+ 0, 0);
+ if ( rv != NO_ERROR )
+ {
+ DosSleep( 50 ); /* Sleep() a few milisecs and try again. */
+ }
+ } /* end for() */
+ return PR_SUCCESS;
+} /* end _PR_MD_LOCKFILE() */
+
+PRStatus
+_PR_MD_TLOCKFILE(PRInt32 f)
+{
+ return _PR_MD_LOCKFILE(f);
+} /* end _PR_MD_TLOCKFILE() */
+
+
+PRStatus
+_PR_MD_UNLOCKFILE(PRInt32 f)
+{
+ PRInt32 rv;
+ FILELOCK lock, unlock;
+
+ lock.lOffset = 0;
+ lock.lRange = 0;
+ unlock.lOffset = 0;
+ unlock.lRange = 0xffffffff;
+
+ rv = DosSetFileLocks( (HFILE) f,
+ &unlock, &lock,
+ 0, 0);
+
+ if ( rv != NO_ERROR )
+ {
+ return PR_SUCCESS;
+ }
+ else
+ {
+ return PR_FAILURE;
+ }
+} /* end _PR_MD_UNLOCKFILE() */
+
+PRStatus
+_PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable)
+{
+ int rv = 0;
+ ULONG flags;
+
+ rv = DosQueryFHState((HFILE)fd->secret->md.osfd, &flags);
+ if (rv != 0) {
+ PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO());
+ return PR_FAILURE;
+ }
+
+ if (inheritable)
+ flags &= ~OPEN_FLAGS_NOINHERIT;
+ else
+ flags |= OPEN_FLAGS_NOINHERIT;
+
+ rv = DosSetFHState((HFILE)fd->secret->md.osfd, flags);
+ if (rv != 0) {
+ PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO());
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
+
+void
+_PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported)
+{
+ /* XXX this function needs to be implemented */
+ fd->secret->inheritable = _PR_TRI_UNKNOWN;
+}
+
+void
+_PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd)
+{
+ /* XXX this function needs to be reviewed */
+ ULONG flags;
+
+ PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable);
+ if (DosQueryFHState((HFILE)fd->secret->md.osfd, &flags) == 0) {
+ if (flags & OPEN_FLAGS_NOINHERIT) {
+ fd->secret->inheritable = _PR_TRI_FALSE;
+ } else {
+ fd->secret->inheritable = _PR_TRI_TRUE;
+ }
+ }
+}