completely shoot nspr

This commit is contained in:
David Rose 2007-03-07 21:57:15 +00:00
parent ce36e31e6a
commit baa0f8039c
83 changed files with 1134 additions and 1779 deletions

View File

@ -162,9 +162,6 @@
#define PYTHON_IPATH /usr/local/include/python2.4
#define PYTHON_LPATH /usr/local/lib/python2.4
#define NSPR_IPATH /usr/local/include/nspr
#define NSPR_LPATH /usr/local/lib/nspr
#define SSL_IPATH /usr/local/openssl
//#define SSL_097 1
@ -190,4 +187,3 @@
//#defer alt_ipath $[alt_ipath] /usr/local/include
//#defer alt_lpath $[alt_lpath] /usr/local/lib
#defer NSPR_LIBS $[NSPR_LIBS] thr

View File

@ -20,7 +20,6 @@
// *******************************************************************
// What additional flags should we pass to interrogate?
// NSPR versions prior to 4.4 used _declspec instead of __declspec.
#define SYSTEM_IGATE_FLAGS -longlong __int64 -D_X86_ -DWIN32_VC -D"_declspec(param)=" -D"__declspec(param)=" -D_near -D_far -D__near -D__far -D_WIN32 -D__stdcall -Dvolatile=
// Additional flags to pass to the Tau instrumentor.

View File

@ -398,22 +398,17 @@
//#defer ALTERNATIVE_MALLOC $[or $[WINDOWS_PLATFORM],$[DO_MEMORY_USAGE],$[not $[HAVE_THREADS]]]
#define ALTERNATIVE_MALLOC
// Is NSPR installed, and where? This is the Netscape Portable
// Runtime library, downloadable as part of the Mozilla package from
// mozilla.org. It provides portable threading and networking
// services to Panda. Panda should compile without it, although
// without any threading or networking capabilities; eventually,
// native support for these capabilities may be added for certain
// platforms. See also HAVE_IPC and HAVE_NET.
#define NSPR_IPATH /usr/include/nspr
#define NSPR_LPATH
#define NSPR_LIBS nspr4
#defer HAVE_NSPR $[isfile $[NSPR_IPATH]/prtypes.h]
// Define this true to build a native network implementation,
// which does not require NSPR.
// Define this true to build the low-level native network
// implementation. Normally this should be set true.
#define WANT_NATIVE_NET 1
#define NATIVE_NET_LIBS $[if $[WINDOWS_PLATFORM],Ws2_32.lib]
#define NATIVE_NET_IPATH
#define NATIVE_NET_LPATH
#define NATIVE_NET_LIBS $[if $[WINDOWS_PLATFORM],wsock32.lib]
// Do you want to build the high-level network interface? This layers
// on top of the low-level native_net interface, specified above.
// Normally, if you build NATIVE_NET, you will also build NET.
#defer HAVE_NET $[WANT_NATIVE_NET]
// Is a third-party STL library installed, and where? This is only
// necessary if the default include and link lines that come with the
@ -683,9 +678,8 @@
// You should only turn this on if you have some threading library
// available (most people will have one). Windows has one built-in.
// Linux uses Posix threads, which most Linuxes provide.
// Alternatively, the NSPR library also provides a threading interface
// that Panda can use.
#define HAVE_THREADS
#define THREADS_LIBS $[if $[not $[WINDOWS_PLATFORM]],pthread]
// Whether threading is defined or not, you might want to validate the
// thread and synchronization operations. With threading enabled,
@ -703,17 +697,6 @@
// than CPU's. Even then, OS-based locking is probably better.
#define MUTEX_SPINLOCK
// Do you want to build the network interface? What additional libraries
// are required? Currently, this requires NSPR.
#define NET_IPATH
#define NET_LPATH
#if $[WINDOWS_PLATFORM]
#define NET_LIBS wsock32.lib
#else
#define NET_LIBS
#endif
#defer HAVE_NET $[HAVE_NSPR]
// Do you want to build the PStats interface, for graphical run-time
// performance statistics? This requires NET to be available. By
// default, we don't build PStats when OPTIMIZE = 4, although this is

View File

@ -11,11 +11,6 @@
#print
#print Configuring support for the following optional third-party packages:
#if $[HAVE_NSPR]
#print + NSPR
#else
#print - Did not find NSPR
#endif
#if $[HAVE_OPENSSL]
#print + OpenSSL
#else
@ -181,9 +176,6 @@ $[cdefine MAYA_PRE_5_0]
/* Define if we have SoftImage available. */
$[cdefine HAVE_SOFTIMAGE]
/* Define if we have NSPR installed. */
$[cdefine HAVE_NSPR]
/* Define if we have OpenSSL installed. */
$[cdefine HAVE_OPENSSL]
$[cdefine OPENSSL_097]

View File

@ -108,10 +108,12 @@
#set PYTHON_FRAMEWORK $[unixfilename $[PYTHON_FRAMEWORK]]
#set HAVE_PYTHON $[HAVE_PYTHON]
#set NSPR_IPATH $[unixfilename $[NSPR_IPATH]]
#set NSPR_LPATH $[unixfilename $[NSPR_LPATH]]
#set NSPR_LIBS $[NSPR_LIBS]
#set HAVE_NSPR $[HAVE_NSPR]
#set NATIVE_NET_IPATH $[unixfilename $[NATIVE_NET_IPATH]]
#set NATIVE_NET_LPATH $[unixfilename $[NATIVE_NET_LPATH]]
#set NATIVE_NET_LIBS $[NATIVE_NET_LIBS]
#set WANT_NATIVE_NET $[WANT_NATIVE_NET]
#set HAVE_NET $[HAVE_NET]
#set OPENSSL_IPATH $[unixfilename $[OPENSSL_IPATH]]
#set OPENSSL_LPATH $[unixfilename $[OPENSSL_LPATH]]
@ -238,11 +240,6 @@
#set DEBUG_THREADS $[DEBUG_THREADS]
#set MUTEX_SPINLOCK $[MUTEX_SPINLOCK]
#set NET_IPATH $[unixfilename $[NET_IPATH]]
#set NET_LPATH $[unixfilename $[NET_LPATH]]
#set NET_LIBS $[NET_LIBS]
#set HAVE_NET $[HAVE_NET]
#set DO_PSTATS $[DO_PSTATS]
#set RAD_MSS_IPATH $[unixfilename $[RAD_MSS_IPATH]]

View File

@ -97,12 +97,12 @@
#define python_framework $[PYTHON_FRAMEWORK]
#endif
#if $[HAVE_NSPR]
#define nspr_ipath $[wildcard $[NSPR_IPATH]]
#define nspr_lpath $[wildcard $[NSPR_LPATH]]
#define nspr_cflags $[NSPR_CFLAGS]
#define nspr_libs $[NSPR_LIBS]
#define nspr_framework $[NSPR_FRAMEWORK]
#if $[HAVE_THREADS]
#define threads_ipath $[wildcard $[THREADS_IPATH]]
#define threads_lpath $[wildcard $[THREADS_LPATH]]
#define threads_cflags $[THREADS_CFLAGS]
#define threads_libs $[THREADS_LIBS]
#define threads_framework $[THREADS_FRAMEWORK]
#endif
#if $[HAVE_OPENSSL]
@ -458,8 +458,8 @@
// on the various external packages this particular target claims to
// require.
#defun get_cflags
// hack to add stl,nspr,python. should be removed
#define alt_cflags $[if $[IGNORE_LIB_DEFAULTS_HACK],,$[stl_cflags] $[nspr_cflags] $[python_cflags]]
// hack to add stl,python. should be removed
#define alt_cflags $[if $[IGNORE_LIB_DEFAULTS_HACK],,$[stl_cflags] $[python_cflags]]
#foreach package $[use_packages]
#set alt_cflags $[alt_cflags] $[$[package]_cflags]
@ -472,8 +472,8 @@
// on the various external packages this particular target claims to
// require.
#defun get_lflags
// hack to add stl,nspr,python. should be removed
#define alt_lflags $[if $[IGNORE_LIB_DEFAULTS_HACK],,$[stl_lflags] $[nspr_lflags] $[python_lflags]]
// hack to add stl,python. should be removed
#define alt_lflags $[if $[IGNORE_LIB_DEFAULTS_HACK],,$[stl_lflags] $[python_lflags]]
#foreach package $[use_packages]
#set alt_lflags $[alt_lflags] $[$[package]_lflags]
@ -487,8 +487,8 @@
// claims to require. This returns a space-separated set of directory
// names only; the -I switch is not included here.
#defun get_ipath
// hack to add stl,nspr,python. should be removed
#define alt_ipath $[if $[IGNORE_LIB_DEFAULTS_HACK],,$[stl_ipath] $[nspr_ipath] $[python_ipath]]
// hack to add stl,python. should be removed
#define alt_ipath $[if $[IGNORE_LIB_DEFAULTS_HACK],,$[stl_ipath] $[python_ipath]]
#foreach package $[use_packages]
#set alt_ipath $[alt_ipath] $[$[package]_ipath]
@ -502,7 +502,7 @@
// target claims to require. This returns a space-separated set of
// directory names only; the -L switch is not included here.
#defun get_lpath
#define alt_lpath $[if $[IGNORE_LIB_DEFAULTS_HACK],,$[stl_lpath] $[nspr_lpath] $[python_lpath]]
#define alt_lpath $[if $[IGNORE_LIB_DEFAULTS_HACK],,$[stl_lpath] $[python_lpath]]
#if $[WINDOWS_PLATFORM]
#set alt_lpath $[WIN32_PLATFORMSDK_LIBPATH] $[alt_lpath]
@ -520,7 +520,7 @@
// target claims to require. This returns a space-separated set of
// directory names only; the -F switch is not included here.
#defun get_fpath
#define alt_fpath $[if $[IGNORE_LIB_DEFAULTS_HACK],,$[stl_fpath] $[nspr_fpath] $[python_fpath]]
#define alt_fpath $[if $[IGNORE_LIB_DEFAULTS_HACK],,$[stl_fpath] $[python_fpath]]
#foreach package $[use_packages]
#set alt_fpath $[alt_fpath] $[$[package]_fpath]
@ -534,7 +534,7 @@
// target claims to require. This returns a space-separated set of
// framework names only; the -framework switch is not included here.
#defun get_frameworks
#define alt_frameworks $[if $[IGNORE_LIB_DEFAULTS_HACK],,$[stl_framework] $[nspr_framework] $[python_framework]]
#define alt_frameworks $[if $[IGNORE_LIB_DEFAULTS_HACK],,$[stl_framework] $[python_framework]]
#if $[OSX_PLATFORM]
#set alt_frameworks $[alt_frameworks] $[OSX_SYS_FRAMEWORKS]
@ -553,7 +553,7 @@
// space-separated set of library names only; the -l switch is not
// included here.
#defun get_libs
#define alt_libs $[if $[IGNORE_LIB_DEFAULTS_HACK],,$[stl_libs] $[nspr_libs] $[python_libs]]
#define alt_libs $[if $[IGNORE_LIB_DEFAULTS_HACK],,$[stl_libs] $[python_libs]]
#define alt_libs $[alt_libs] $[EXTRA_LIBS]

View File

@ -1,4 +1,5 @@
#define SELECT_TAU select.tau
#define USE_PACKAGES threads
#begin lib_target
#define TARGET dtoolbase
@ -10,7 +11,6 @@
atomicAdjust.h \
atomicAdjustDummyImpl.h atomicAdjustDummyImpl.I \
atomicAdjustI386Impl.h atomicAdjustI386Impl.I \
atomicAdjustNsprImpl.h atomicAdjustNsprImpl.I \
atomicAdjustPosixImpl.h atomicAdjustPosixImpl.I \
atomicAdjustWin32Impl.h atomicAdjustWin32Impl.I \
cmath.I cmath.h \
@ -22,7 +22,6 @@
memoryBase.h \
mutexImpl.h \
mutexDummyImpl.h mutexDummyImpl.I \
mutexNsprImpl.h mutexNsprImpl.I \
mutexLinuxImpl.h mutexLinuxImpl.I \
mutexPosixImpl.h mutexPosixImpl.I \
mutexWin32Impl.h mutexWin32Impl.I \
@ -44,13 +43,11 @@
addHash.cxx \
atomicAdjustDummyImpl.cxx \
atomicAdjustI386Impl.cxx \
atomicAdjustNsprImpl.cxx \
atomicAdjustPosixImpl.cxx \
atomicAdjustWin32Impl.cxx \
dtoolbase.cxx \
memoryBase.cxx \
mutexDummyImpl.cxx \
mutexNsprImpl.cxx \
mutexLinuxImpl.cxx \
mutexPosixImpl.cxx \
mutexWin32Impl.cxx \
@ -65,7 +62,6 @@
atomicAdjust.h \
atomicAdjustDummyImpl.h atomicAdjustDummyImpl.I \
atomicAdjustI386Impl.h atomicAdjustI386Impl.I \
atomicAdjustNsprImpl.h atomicAdjustNsprImpl.I \
atomicAdjustPosixImpl.h atomicAdjustPosixImpl.I \
atomicAdjustWin32Impl.h atomicAdjustWin32Impl.I \
cmath.I cmath.h \
@ -76,7 +72,6 @@
memoryBase.h \
mutexImpl.h \
mutexDummyImpl.h mutexDummyImpl.I \
mutexNsprImpl.h mutexNsprImpl.I \
mutexLinuxImpl.h mutexLinuxImpl.I \
mutexPosixImpl.h mutexPosixImpl.I \
mutexWin32Impl.h mutexWin32Impl.I \

View File

@ -60,11 +60,6 @@ typedef AtomicAdjustWin32Impl AtomicAdjust;
#include "atomicAdjustPosixImpl.h"
typedef AtomicAdjustPosixImpl AtomicAdjust;
#elif defined(THREAD_NSPR_IMPL)
#include "atomicAdjustNsprImpl.h"
typedef AtomicAdjustNsprImpl AtomicAdjust;
#endif
#endif

View File

@ -1,140 +0,0 @@
// Filename: atomicAdjustNsprImpl.I
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustNsprImpl::inc
// Access: Public, Static
// Description: Atomically increments the indicated variable.
////////////////////////////////////////////////////////////////////
INLINE void AtomicAdjustNsprImpl::
inc(TVOLATILE PN_int32 &var) {
PR_AtomicIncrement((PRInt32 *)&var);
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustNsprImpl::dec
// Access: Public, Static
// Description: Atomically decrements the indicated variable and
// returns true if the new value is nonzero, false if it
// is zero.
////////////////////////////////////////////////////////////////////
INLINE bool AtomicAdjustNsprImpl::
dec(TVOLATILE PN_int32 &var) {
return (PR_AtomicDecrement((PRInt32 *)&var) != 0);
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustNsprImpl::set
// Access: Public, Static
// Description: Atomically changes the indicated variable and
// returns the original value.
////////////////////////////////////////////////////////////////////
INLINE PN_int32 AtomicAdjustNsprImpl::
set(TVOLATILE PN_int32 &var, PN_int32 new_value) {
return PR_AtomicSet((PRInt32 *)&var, new_value);
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustNsprImpl::get
// Access: Public, Static
// Description: Atomically retrieves the snapshot value of the
// indicated variable. This is the only guaranteed safe
// way to retrieve the value that other threads might be
// asynchronously setting, incrementing, or decrementing
// (via other AtomicAjust methods).
////////////////////////////////////////////////////////////////////
INLINE PN_int32 AtomicAdjustNsprImpl::
get(const TVOLATILE PN_int32 &var) {
return var;
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustNsprImpl::set_ptr
// Access: Public, Static
// Description: Atomically changes the indicated variable and
// returns the original value.
////////////////////////////////////////////////////////////////////
INLINE void *AtomicAdjustNsprImpl::
set_ptr(void * TVOLATILE &var, void *new_value) {
return (void *)PR_AtomicSet((PRInt32 *)&var, (PRInt32)new_value);
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustNsprImpl::get_ptr
// Access: Public, Static
// Description: Atomically retrieves the snapshot value of the
// indicated variable. This is the only guaranteed safe
// way to retrieve the value that other threads might be
// asynchronously setting, incrementing, or decrementing
// (via other AtomicAjust methods).
////////////////////////////////////////////////////////////////////
INLINE void *AtomicAdjustNsprImpl::
get_ptr(void * const TVOLATILE &var) {
return var;
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustNsprImpl::compare_and_exchange
// Access: Public, Static
// Description: Atomic compare and exchange.
//
// If mem is equal to old_value, store new_value in mem.
// In either case, return the original value of mem.
// The caller can test for success by comparing
// return_value == old_value.
//
// The atomic function expressed in pseudo-code:
//
// orig_value = mem;
// if (mem == old_value) {
// mem = new_value;
// }
// return orig_value;
//
////////////////////////////////////////////////////////////////////
INLINE PN_int32 AtomicAdjustNsprImpl::
compare_and_exchange(TVOLATILE PN_int32 &mem, PN_int32 old_value,
PN_int32 new_value) {
PR_Lock(_mutex);
PN_int32 orig_value = mem;
if (mem == old_value) {
mem = new_value;
}
PR_Unlock(_mutex);
return orig_value;
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustNsprImpl::compare_and_exchange_ptr
// Access: Public, Static
// Description: Atomic compare and exchange.
//
// As above, but works on pointers instead of integers.
////////////////////////////////////////////////////////////////////
INLINE void *AtomicAdjustNsprImpl::
compare_and_exchange_ptr(void * TVOLATILE &mem, void *old_value,
void *new_value) {
PR_Lock(_mutex);
void *orig_value = mem;
if (mem == old_value) {
mem = new_value;
}
PR_Unlock(_mutex);
return orig_value;
}

View File

@ -1,62 +0,0 @@
// Filename: atomicAdjustNsprImpl.h
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef ATOMICADJUSTNSPRIMPL_H
#define ATOMICADJUSTNSPRIMPL_H
#include "dtoolbase.h"
#include "selectThreadImpl.h"
#ifdef HAVE_NSPR
#include "numeric_types.h"
#include <pratom.h>
#include <prlock.h>
////////////////////////////////////////////////////////////////////
// Class : AtomicAdjustNsprImpl
// Description : Uses NSPR to implement atomic adjustments.
////////////////////////////////////////////////////////////////////
class EXPCL_DTOOL AtomicAdjustNsprImpl {
public:
INLINE static void inc(TVOLATILE PN_int32 &var);
INLINE static bool dec(TVOLATILE PN_int32 &var);
INLINE static PN_int32 set(TVOLATILE PN_int32 &var, PN_int32 new_value);
INLINE static PN_int32 get(const TVOLATILE PN_int32 &var);
INLINE static void *set_ptr(void * TVOLATILE &var, void *new_value);
INLINE static void *get_ptr(void * const TVOLATILE &var);
INLINE static PN_int32 compare_and_exchange(TVOLATILE PN_int32 &mem,
PN_int32 old_value,
PN_int32 new_value);
INLINE static void *compare_and_exchange_ptr(void * TVOLATILE &mem,
void *old_value,
void *new_value);
private:
static PRLock *_mutex;
};
#include "atomicAdjustNsprImpl.I"
#endif // HAVE_NSPR
#endif

View File

@ -1,7 +1,6 @@
#include "addHash.cxx"
#include "atomicAdjustDummyImpl.cxx"
#include "atomicAdjustI386Impl.cxx"
#include "atomicAdjustNsprImpl.cxx"
#include "atomicAdjustPosixImpl.cxx"
#include "atomicAdjustWin32Impl.cxx"
#include "dtoolbase.cxx"

View File

@ -1,5 +1,4 @@
#include "mutexDummyImpl.cxx"
#include "mutexNsprImpl.cxx"
#include "mutexLinuxImpl.cxx"
#include "mutexPosixImpl.cxx"
#include "mutexWin32Impl.cxx"

View File

@ -55,13 +55,6 @@ typedef MutexPosixImpl MutexImpl;
typedef ReMutexPosixImpl ReMutexImpl;
#define HAVE_REMUTEXIMPL 1
#elif defined(THREAD_NSPR_IMPL)
#include "mutexNsprImpl.h"
typedef MutexNsprImpl MutexImpl;
typedef ReMutexNsprImpl ReMutexImpl;
#define HAVE_REMUTEXIMPL 1
#endif
#endif

View File

@ -1,126 +0,0 @@
// Filename: mutexNsprImpl.I
// Created by: drose (08Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: MutexNsprImpl::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE MutexNsprImpl::
MutexNsprImpl() {
_lock = PR_NewLock();
assert(_lock != (PRLock *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: MutexNsprImpl::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE MutexNsprImpl::
~MutexNsprImpl() {
PR_DestroyLock(_lock);
}
////////////////////////////////////////////////////////////////////
// Function: MutexNsprImpl::lock
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void MutexNsprImpl::
lock() {
PR_Lock(_lock);
}
////////////////////////////////////////////////////////////////////
// Function: MutexNsprImpl::try_lock
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool MutexNsprImpl::
try_lock() {
// NSPR doesn't define a try_lock function. Too bad. We just
// report that it would always block (since we don't know).
return false;
}
////////////////////////////////////////////////////////////////////
// Function: MutexNsprImpl::release
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void MutexNsprImpl::
release() {
int status = PR_Unlock(_lock);
assert(status == PR_SUCCESS);
}
////////////////////////////////////////////////////////////////////
// Function: ReMutexNsprImpl::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE ReMutexNsprImpl::
ReMutexNsprImpl() {
_monitor = PR_NewMonitor();
assert(_monitor != (PRMonitor *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: ReMutexNsprImpl::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE ReMutexNsprImpl::
~ReMutexNsprImpl() {
PR_DestroyMonitor(_monitor);
}
////////////////////////////////////////////////////////////////////
// Function: ReMutexNsprImpl::lock
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void ReMutexNsprImpl::
lock() {
PR_EnterMonitor(_monitor);
}
////////////////////////////////////////////////////////////////////
// Function: ReMutexNsprImpl::try_lock
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool ReMutexNsprImpl::
try_lock() {
// NSPR doesn't define a try_lock function. Too bad. We just
// report that it would always block (since we don't know).
return false;
}
////////////////////////////////////////////////////////////////////
// Function: ReMutexNsprImpl::release
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void ReMutexNsprImpl::
release() {
int status = PR_ExitMonitor(_monitor);
assert(status == PR_SUCCESS);
}

View File

@ -1,70 +0,0 @@
// Filename: mutexNsprImpl.h
// Created by: drose (08Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef MUTEXNSPRIMPL_H
#define MUTEXNSPRIMPL_H
#include "dtoolbase.h"
#include "selectThreadImpl.h"
#ifdef HAVE_NSPR
#include <prlock.h>
#include <prmon.h>
#include <assert.h>
////////////////////////////////////////////////////////////////////
// Class : MutexNsprImpl
// Description : Uses NSPR to implement a mutex.
////////////////////////////////////////////////////////////////////
class EXPCL_DTOOL MutexNsprImpl {
public:
INLINE MutexNsprImpl();
INLINE ~MutexNsprImpl();
INLINE void lock();
INLINE bool try_lock();
INLINE void release();
private:
PRLock *_lock;
friend class ConditionVarNsprImpl;
};
////////////////////////////////////////////////////////////////////
// Class : ReMutexNsprImpl
// Description : Uses NSPR to implement a reMutex.
////////////////////////////////////////////////////////////////////
class EXPCL_DTOOL ReMutexNsprImpl {
public:
INLINE ReMutexNsprImpl();
INLINE ~ReMutexNsprImpl();
INLINE void lock();
INLINE bool try_lock();
INLINE void release();
private:
PRMonitor *_monitor;
};
#include "mutexNsprImpl.I"
#endif // HAVE_NSPR
#endif

View File

@ -25,34 +25,7 @@
// the various numeric types for unsigned and signed numbers of
// various widths.
// At the present, we use the logic in NSPR to determine this for us.
// Later (especially for non-NSPR platforms) we'll have to do the work
// ourselves.
#ifdef HAVE_NSPR
#include <prtypes.h>
typedef PRInt8 PN_int8;
typedef PRInt16 PN_int16;
typedef PRInt32 PN_int32;
typedef PRInt64 PN_int64;
typedef PRUint8 PN_uint8;
typedef PRUint16 PN_uint16;
typedef PRUint32 PN_uint32;
typedef PRUint64 PN_uint64;
typedef PRFloat64 PN_float64;
// NSPR doesn't define a float32.
typedef float PN_float32;
#else // HAVE_NSPR
// Without NSPR, and without any other information, we need some
// fallback. For now, we'll just assume a typical environment.
// For now, we'll just assume a typical 32-bit environment.
typedef signed char PN_int8;
typedef short PN_int16;
@ -73,8 +46,6 @@ typedef unsigned long long PN_uint64;
typedef double PN_float64;
typedef float PN_float32;
#endif // HAVE_NSPR
#endif

View File

@ -64,11 +64,6 @@
// Posix threads are nice.
#define THREAD_POSIX_IMPL 1
#elif defined(HAVE_NSPR)
// If NSPR is available, use that.
#define THREAD_NSPR_IMPL 1
#else
// This is a configuration error. For some reason, HAVE_THREADS is

View File

@ -3,7 +3,9 @@
pair pthread.h queue set stack stdcompare.h stdtypedefs.h \
string vector windows.h winsock2.h zlib.h files.h hex.h \
md5.h evp.h bits/pthreadtypes.h \
openssl/md5.h openssl/evp.h openssl/rand.h openssl/ssl.h openssl/x509.h openssl/err.h \
openssl/md5.h openssl/evp.h openssl/rand.h openssl/ssl.h \
openssl/x509.h openssl/err.h openssl/rsa.h openssl/crypto.h \
openssl/pem.h \
nurbs.hh stddef.h krb5.h MainHelix.h dllpath.h hxcom.h \
hxcomm.h hxcore.h hxengin.h hxerror.h hxfiles.h hxtbuf.h \
hxtbuff.h hxwin.h Python.h Cg/cg.h Cg/cgGL.h \

View File

View File

View File

View File

@ -9,5 +9,6 @@ struct EVP_PKEY;
struct X509;
struct X509_STORE;
struct X509_NAME;
struct SSL;
#endif

View File

@ -4,7 +4,7 @@
#begin lib_target
#define TARGET express
#define USE_PACKAGES nspr net zlib openssl
#define USE_PACKAGES zlib openssl
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx

View File

@ -5,7 +5,7 @@
dtoolutil:c dtoolbase:c prc:c dtool:m
#define BUILD_DIRECTORY $[WANT_NATIVE_NET]
#define USE_PACKAGES native_net
#define USE_PACKAGES native_net openssl
#begin lib_target
#define TARGET nativenet
@ -19,12 +19,22 @@
socket_tcp_listen.h time_accumulator.h time_out.h \
socket_address.h \
socket_portable.h time_base.h time_span.h buffered_datagramwriter.h \
socket_base.h socket_selector.h socket_udp_incoming.h time_clock.h \
socket_base.h socket_selector.h \
socket_udp.h \
socket_udp_incoming.h time_clock.h \
membuffer.h membuffer.i socket_fdset.h socket_tcp.h \
socket_udp_outgoing.h time_general.h
#define INCLUDED_SOURCES \
buffered_datagramconnection.cxx \
config_nativenet.cxx \
socket_ip.cxx \
socket_tcp.cxx \
socket_tcp_listen.cxx \
socket_tcp_ssl.cxx \
socket_udp.cxx \
socket_udp_incoming.cxx \
socket_udp_outgoing.cxx
#define INSTALL_HEADERS \
buffered_datagramconnection.h \
@ -33,7 +43,9 @@
buffered_datagramreader.h buffered_datagramreader.i \
socket_address.h \
socket_portable.h time_base.h time_span.h buffered_datagramwriter.h \
socket_base.h socket_selector.h socket_udp_incoming.h time_clock.h \
socket_base.h socket_selector.h \
socket_udp.h \
socket_udp_incoming.h time_clock.h \
membuffer.h membuffer.i socket_fdset.h socket_tcp.h \
socket_udp_outgoing.h time_general.h

View File

@ -0,0 +1,21 @@
// Filename: buffered_datagramconnection.cxx
// Created by: drose (05Mar07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "buffered_datagramconnection.h"
TypeHandle Buffered_DatagramConnection::_type_handle;

View File

@ -26,7 +26,7 @@
// 3. Socket is open and writable.. ( Fully powered up )...
//
///////////////////////////////////////////////////////////////
class EXPCL_PANDA Buffered_DatagramConnection : protected Socket_TCP
class EXPCL_PANDA Buffered_DatagramConnection : public Socket_TCP
{
private:
struct AddressQueue : private pvector<Socket_Address> // this is used to do a round robin for addres to connect to ..
@ -89,7 +89,24 @@ private:
friend class Buffered_DatagramReader;
friend class Buffered_DatagramWriter;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
Socket_IP::init_type();
register_type(_type_handle, "Buffered_DatagramConnection",
Socket_IP::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
////////////////////////////////////////////////////////////////////
// Function name : Buffered_DatagramConnection::ClearAll
// Description : used to do a full reset of buffers

View File

@ -0,0 +1,72 @@
// Filename: config_nativenet.cxx
// Created by: drose (01Mar07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "config_nativenet.h"
#include "socket_ip.h"
#include "socket_tcp.h"
#include "socket_tcp_listen.h"
#include "socket_tcp_ssl.h"
#include "socket_udp_incoming.h"
#include "socket_udp_outgoing.h"
#include "socket_udp.h"
#include "socket_portable.h"
#include "buffered_datagramconnection.h"
#include "pandaSystem.h"
#include "dconfig.h"
Configure(config_nativenet);
NotifyCategoryDef(nativenet, "");
ConfigureFn(config_nativenet) {
init_libnativenet();
}
////////////////////////////////////////////////////////////////////
// Function: init_libnativenet
// Description: Initializes the library. This must be called at
// least once before any of the functions or classes in
// this library can be used. Normally it will be
// called by the static initializers and need not be
// called explicitly, but special cases exist.
////////////////////////////////////////////////////////////////////
void
init_libnativenet() {
static bool initialized = false;
if (initialized) {
return;
}
initialized = true;
Socket_IP::init_type();
Socket_TCP::init_type();
Socket_TCP_Listen::init_type();
Socket_TCP_SSL::init_type();
Socket_UDP_Incoming::init_type();
Socket_UDP_Outgoing::init_type();
Socket_UDP::init_type();
Buffered_DatagramConnection::init_type();
PandaSystem *ps = PandaSystem::get_global_ptr();
ps->add_system("nativenet");
init_network();
}

View File

@ -0,0 +1,32 @@
// Filename: config_nativenet.h
// Created by: drose (01Mar07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef CONFIG_NATIVENET_H
#define CONFIG_NATIVENET_H
#include "pandabase.h"
#include "notifyCategoryProxy.h"
// Configure variables for nativenet package.
NotifyCategoryDecl(nativenet, EXPCL_PANDA, EXPTP_PANDA);
extern EXPCL_PANDA void init_libnativenet();
#endif

View File

@ -1,3 +1,9 @@
#include "socket_base.h"
#include "buffered_datagramconnection.cxx"
#include "config_nativenet.cxx"
#include "socket_ip.cxx"
#include "socket_tcp.cxx"
#include "socket_tcp_listen.cxx"
#include "socket_tcp_ssl.cxx"
#include "socket_udp.cxx"
#include "socket_udp_incoming.cxx"
#include "socket_udp_outgoing.cxx"

View File

@ -3,6 +3,7 @@
#include "pandabase.h"
#include "numeric_types.h"
#include "socket_portable.h"
///////////////////////////////////
// Class : Socket_Address

View File

@ -14,6 +14,7 @@
#include "pandabase.h"
#include "numeric_types.h"
#include "time_base.h"
#include "socket_ip.h"
class Socket_fdset
{

View File

@ -1,5 +1,5 @@
// Filename: mutexNsprImpl.cxx
// Created by: drose (09Aug02)
// Filename: socket_ip.cxx
// Created by: drose (01Mar07)
//
////////////////////////////////////////////////////////////////////
//
@ -16,10 +16,6 @@
//
////////////////////////////////////////////////////////////////////
#include "selectThreadImpl.h"
#include "socket_ip.h"
#ifdef HAVE_NSPR
#include "mutexNsprImpl.h"
#endif // HAVE_NSPR
TypeHandle Socket_IP::_type_handle;

View File

@ -1,6 +1,11 @@
#ifndef __SOCKET_IP_H__
#define __SOCKET_IP_H__
#include "pandabase.h"
#include "socket_portable.h"
#include "socket_address.h"
#include "typedObject.h"
// forward declarations for friends...
class Socket_TCP;
class Socket_UDP;
@ -26,8 +31,7 @@ class Socket_UDP_Outgoing;
// socket_fdset
//
/////////////////////////////////////////////////////////////////////
class EXPCL_PANDA Socket_IP
{
class EXPCL_PANDA Socket_IP : public TypedObject {
public:
PUBLISHED:
@ -39,7 +43,7 @@ PUBLISHED:
inline static int GetLastError();
inline int SetNonBlocking();
inline int SetBlocking();
inline bool SetReuseAddress();
inline bool SetReuseAddress(bool flag = true);
inline bool Active();
inline int SetRecvBufferSize(int size);
inline void SetSocket(SOCKET ins);
@ -62,6 +66,23 @@ private:
friend class Socket_UDP_Incoming;
friend class Socket_UDP_Outgoing;
friend class Socket_TCP_SSL;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
TypedObject::init_type();
register_type(_type_handle, "Socket_IP",
TypedObject::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
////////////////////////////////////////////////////////////////////
@ -204,9 +225,9 @@ inline int Socket_IP::SetBlocking()
// Function name : SetReuseAddress
// Description : Informs a socket to reuse IP address as needed
////////////////////////////////////////////////////////////////////
inline bool Socket_IP::SetReuseAddress()
inline bool Socket_IP::SetReuseAddress(bool flag)
{
int bOption = 1;
int bOption = flag;
if (setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&bOption, sizeof(bOption)) != 0)
return false;
return true;

View File

@ -1,5 +1,5 @@
// Filename: pprerror.h
// Created by: drose (08Feb00)
// Filename: socket_tcp.cxx
// Created by: drose (01Mar07)
//
////////////////////////////////////////////////////////////////////
//
@ -16,12 +16,6 @@
//
////////////////////////////////////////////////////////////////////
#ifndef PPRERROR_H
#define PPRERROR_H
#include "pandabase.h"
void pprerror(const char *format, ...);
#endif
#include "socket_tcp.h"
TypeHandle Socket_TCP::_type_handle;

View File

@ -1,6 +1,9 @@
#ifndef __SOCKET_TCP_H__
#define __SOCKET_TCP_H__
#include "pandabase.h"
#include "socket_ip.h"
/////////////////////////////////////////////////////////////////////
// Class : Socket_TCP
//
@ -15,7 +18,7 @@ public:
PUBLISHED:
inline Socket_TCP(SOCKET);
inline Socket_TCP() { };
inline int SetNoDelay();
inline int SetNoDelay(bool flag = true);
inline int SetLinger(int interval_seconds = 0);
inline int DontLinger();
inline int SetSendBufferSize(int insize);
@ -30,6 +33,23 @@ PUBLISHED:
public:
inline int SendData(const char * data, int size);
inline int RecvData(char * data, int size);
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
Socket_IP::init_type();
register_type(_type_handle, "Socket_TCP",
Socket_IP::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
//////////////////////////////////////////////////////////////
@ -44,9 +64,9 @@ inline Socket_TCP::Socket_TCP(SOCKET sck) : ::Socket_IP(sck)
// Function name : SetNoDelay
// Description : Disable Nagle algorithm. Don't delay send to coalesce packets
////////////////////////////////////////////////////////////////////
inline int Socket_TCP::SetNoDelay()
inline int Socket_TCP::SetNoDelay(bool flag)
{
int nodel = 1;
int nodel = flag;
int ret1;
ret1 = setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (char *) & nodel, sizeof(nodel));

View File

@ -0,0 +1,21 @@
// Filename: socket_tcp_listen.cxx
// Created by: drose (01Mar07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "socket_tcp_listen.h"
TypeHandle Socket_TCP_Listen::_type_handle;

View File

@ -1,6 +1,9 @@
#ifndef __SOCKET_TCP_LISTEN_H__
#define __SOCKET_TCP_LISTEN_H__
#include "pandabase.h"
#include "socket_ip.h"
/////////////////////////////////////////////////////////////////////
// Class : Socket_TCP_Listen
// Description : Base functionality for a TCP rendezvous socket
@ -11,29 +14,48 @@ public:
PUBLISHED:
Socket_TCP_Listen() {};
~Socket_TCP_Listen() {};
inline bool OpenForListen(Socket_Address & Inaddess, int backlog_size = 1024);
inline bool OpenForListen(const Socket_Address & Inaddess, int backlog_size = 1024);
inline bool GetIncomingConnection(Socket_TCP & newsession, Socket_Address &address);
public:
inline bool GetIncomingConnection(SOCKET & newsession, Socket_Address &address);
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
Socket_IP::init_type();
register_type(_type_handle, "Socket_TCP_Listen",
Socket_IP::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
////////////////////////////////////////////////////////////////////
// Function name : OpenForListen
// Description : This function will initialize a listening Socket
////////////////////////////////////////////////////////////////////
inline bool Socket_TCP_Listen::OpenForListen(Socket_Address & Inaddess, int backlog_size )
inline bool Socket_TCP_Listen::OpenForListen(const Socket_Address & Inaddess, int backlog_size )
{
ErrorClose();
_socket = DO_NEWTCP();
SetReuseAddress();
if (DO_BIND(_socket, &Inaddess.GetAddressInfo()) != 0)
return ErrorClose();
if (DO_LISTEN(_socket, backlog_size) != 0)
return ErrorClose();
if (DO_BIND(_socket, &Inaddess.GetAddressInfo()) != 0) {
return ErrorClose();
}
if (DO_LISTEN(_socket, backlog_size) != 0) {
return ErrorClose();
}
return true;
}
////////////////////////////////////////////////////////////////////

View File

@ -1,5 +1,5 @@
// Filename: atomicAdjustNsprImpl.cxx
// Created by: drose (09Aug02)
// Filename: socket_tcp_ssl.cxx
// Created by: drose (01Mar07)
//
////////////////////////////////////////////////////////////////////
//
@ -16,12 +16,11 @@
//
////////////////////////////////////////////////////////////////////
#include "selectThreadImpl.h"
#include "socket_tcp_ssl.h"
#ifdef HAVE_NSPR
#ifdef HAVE_OPENSSL
#include "atomicAdjustNsprImpl.h"
SSL_CTX *global_ssl_ctx;
TypeHandle Socket_TCP_SSL::_type_handle;
PRLock *AtomicAdjustNsprImpl::_mutex = PR_NewLock();
#endif // HAVE_NSPR
#endif // HAVE_OPENSSL

View File

@ -1,17 +1,12 @@
#ifndef __SOCKET_TCP_SSL_H__
#define __SOCKET_TCP_SSL_H__
/////////////////////////////////////////////////////////////////////
// Class : Socket_TCP
//
// Description : Base functionality for a TCP connected socket
// This class is pretty useless by itself but it does hide some of the
// platform differences from machine to machine
//
/////////////////////////////////////////////////////////////////////
#include "pandabase.h"
#include "socket_ip.h"
#include "numeric_types.h"
#ifdef HAVE_OPENSSL
#include <openssl/rsa.h> /* SSLeay stuff */
#include <openssl/crypto.h>
#include <openssl/x509.h>
@ -19,9 +14,14 @@
#include <openssl/ssl.h>
#include <openssl/err.h>
/////////////////////////////////////////////////////////////////////
// Class : Socket_TCP_SSL
//
// Description :
//
/////////////////////////////////////////////////////////////////////
extern SSL_CTX *global_ssl_ctx;
extern EXPCL_PANDA SSL_CTX *global_ssl_ctx;
struct SSlStartup
@ -47,7 +47,7 @@ struct SSlStartup
};
class Socket_TCP_SSL : public Socket_IP
class EXPCL_PANDA Socket_TCP_SSL : public Socket_IP
{
public:
@ -84,6 +84,23 @@ private:
_ssl = NULL;
}
}
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
Socket_IP::init_type();
register_type(_type_handle, "Socket_TCP_SSL",
Socket_IP::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
//////////////////////////////////////////////////////////////
@ -101,7 +118,7 @@ inline Socket_TCP_SSL::Socket_TCP_SSL(SOCKET sck) : ::Socket_IP(sck)
return;
SSL_set_fd (_ssl,(int)GetSocket() );
int err = SSL_accept(_ssl);
SSL_accept(_ssl);
ERR_clear_error();
// printf(" Ssl Accept = %d \n",err);
@ -244,7 +261,9 @@ inline bool Socket_TCP_SSL::ErrorIs_WouldBlocking(int err)
{
if(_ssl == NULL || err >= 0)
{
LOGWARNING("Socket_TCP_SSL::ErrorIs_WouldBlocking->Called With Error numebr %d or _ssl is NULL",err);
nativenet_cat.warning()
<< "Socket_TCP_SSL::ErrorIs_WouldBlocking->Called With Error number "
<< err << " or _ssl is NULL\n";
return false;
}
@ -296,9 +315,13 @@ inline void Socket_TCP_SSL::DetailErrorFormat(void)
{
ERR_error_string_n(l, buf, sizeof( buf) );
BIO_snprintf(buf2, sizeof(buf2), "***%lu:%s:%s:%d:%s\n", es, buf,file, line, (flags & ERR_TXT_STRING) ? data : "NoText");
LOGWARNING("Socket_TCP_SSL::DetailErrorFormat->[%s]",buf2);
nativenet_cat.warning()
<< "Socket_TCP_SSL::DetailErrorFormat->[" << buf2 << "]\n";
}
}
#endif // HAVE_OPENSSL
#endif //__SOCKET_TCP_SSL_H__

View File

@ -0,0 +1,21 @@
// Filename: socket_udp.cxx
// Created by: drose (01Mar07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "socket_udp.h"
TypeHandle Socket_UDP::_type_handle;

View File

@ -0,0 +1,169 @@
// Filename: socket_udp.h
// Created by: drose (01Mar07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef __SOCKET_UDP_H__
#define __SOCKET_UDP_H__
#include "socket_udp_incoming.h"
/////////////////////////////////////////////////////////////////////
// Class : Socket_UDP
//
// Description : Base functionality for a combination UDP Reader and
// Writer. This duplicates code from
// Socket_UDP_Outgoing, to avoid the problems of
// multiple inheritance.
/////////////////////////////////////////////////////////////////////
class EXPCL_PANDA Socket_UDP : public Socket_UDP_Incoming
{
public:
PUBLISHED:
inline Socket_UDP() { }
// use this interface for a tagreted UDP connection
inline bool InitToAddress(const Socket_Address & address);
public:
inline bool Send(const char * data, int len);
PUBLISHED:
inline bool Send(const string &data);
// use this interface for a none tagreted UDP connection
inline bool InitNoAddress();
public:
inline bool SendTo(const char * data, int len, const Socket_Address & address);
PUBLISHED:
inline bool SendTo(const string &data, const Socket_Address & address);
inline bool SetToBroadCast();
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
Socket_UDP_Incoming::init_type();
register_type(_type_handle, "Socket_UDP",
Socket_UDP_Incoming::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
//////////////////////////////////////////////////////////////
// Function name : Socket_UDP:SetToBroadCast
// Description : Ask the OS to let us receive BROADCASt packets on this port..
// Return type : bool
// Argument : void
//////////////////////////////////////////////////////////////
inline bool Socket_UDP::SetToBroadCast()
{
int optval = 1;
if (setsockopt(_socket, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)) != 0)
return false;
return true;
}
////////////////////////////////////////////////////////////////////
// Function name : Socket_UDP::InitToAddress
// Description : Connects the Socket to a Specified address
//
// Return type : inline bool
// Argument : NetAddress & address
////////////////////////////////////////////////////////////////////
inline bool Socket_UDP::InitToAddress(const Socket_Address & address)
{
if (InitNoAddress() != true)
return false;
if (DO_CONNECT(_socket, &address.GetAddressInfo()) != 0)
return ErrorClose();
return true;
}
////////////////////////////////////////////////////////////////////
// Function name : Socket_UDP::InitNoAddress
// Description : This will set a udp up for targeted sends..
//
// Return type : inline bool
// Argument : void
////////////////////////////////////////////////////////////////////
inline bool Socket_UDP::InitNoAddress()
{
Close();
_socket = DO_NEWUDP();
if (_socket == BAD_SOCKET)
return false;
return true;
}
////////////////////////////////////////////////////////////////////
// Function name : Socket_UDP::Send
// Description : Send data to connected address
//
// Return type : inline bool
// Argument : char * data
// Argument : int len
////////////////////////////////////////////////////////////////////
inline bool Socket_UDP::Send(const char * data, int len)
{
return (DO_SOCKET_WRITE(_socket, data, len) == len);
}
////////////////////////////////////////////////////////////////////
// Function name : Socket_UDP::Send
// Description : Send data to connected address
//
// Return type : inline bool
// Argument : const string &data
////////////////////////////////////////////////////////////////////
inline bool Socket_UDP::Send(const string &data)
{
return Send(data.data(), data.size());
}
////////////////////////////////////////////////////////////////////
// Function name : Socket_UDP::SendTo
// Description : Send data to specified address
//
// Return type : inline bool
// Argument : char * data
// Argument : int len
// Argument : NetAddress & address
////////////////////////////////////////////////////////////////////
inline bool Socket_UDP::SendTo(const char * data, int len, const Socket_Address & address)
{
return (DO_SOCKET_WRITE_TO(_socket, data, len, &address.GetAddressInfo()) == len);
}
////////////////////////////////////////////////////////////////////
// Function name : Socket_UDP::SendTo
// Description : Send data to specified address
//
// Return type : inline bool
// Argument : const string &data
// Argument : NetAddress & address
////////////////////////////////////////////////////////////////////
inline bool Socket_UDP::SendTo(const string &data, const Socket_Address & address)
{
return SendTo(data.data(), data.size(), address);
}
#endif //__SOCKET_UDP_H__

View File

@ -0,0 +1,21 @@
// Filename: socket_udp_incoming.cxx
// Created by: drose (01Mar07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "socket_udp_incoming.h"
TypeHandle Socket_UDP_Incoming::_type_handle;

View File

@ -1,5 +1,9 @@
#ifndef __SOCKET_UDP_INCOMING_H__
#define __SOCKET_UDP_INCOMING_H__
#include "pandabase.h"
#include "socket_ip.h"
/////////////////////////////////////////////////////////////////////
// Class : Socket_UDP_Incoming
//
@ -7,17 +11,36 @@
//
//
/////////////////////////////////////////////////////////////////////
class Socket_UDP_Incoming : public Socket_IP
class EXPCL_PANDA Socket_UDP_Incoming : public Socket_IP
{
public:
PUBLISHED:
inline bool OpenForInput(Socket_Address & address);
inline bool OpenForInputMCast(Socket_Address & address );
inline Socket_UDP_Incoming() { }
inline bool OpenForInput(const Socket_Address & address);
inline bool OpenForInputMCast(const Socket_Address & address );
inline bool GetPacket(char * data, int *max_len, Socket_Address & address);
inline bool SendTo(const char * data, int len, const Socket_Address & address);
inline bool InitNoAddress();
inline bool SetToBroadCast();
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
Socket_IP::init_type();
register_type(_type_handle, "Socket_UDP_Incoming",
Socket_IP::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
//////////////////////////////////////////////////////////////
// Function name : Socket_UDP_Incoming::tToBroadCast
// Description : Flips the OS bits that allow for brodcast
@ -57,7 +80,7 @@ inline bool Socket_UDP_Incoming::InitNoAddress()
// Return type : bool
// Argument : NetAddress & address
////////////////////////////////////////////////////////////////////
inline bool Socket_UDP_Incoming::OpenForInput(Socket_Address & address)
inline bool Socket_UDP_Incoming::OpenForInput(const Socket_Address & address)
{
Close();
_socket = DO_NEWUDP();
@ -77,7 +100,7 @@ inline bool Socket_UDP_Incoming::OpenForInput(Socket_Address & address)
// Return type : bool
// Argument : NetAddress & address
////////////////////////////////////////////////////////////////////
inline bool Socket_UDP_Incoming::OpenForInputMCast(Socket_Address & address)
inline bool Socket_UDP_Incoming::OpenForInputMCast(const Socket_Address & address)
{
Close();
_socket = DO_NEWUDP();

View File

@ -0,0 +1,21 @@
// Filename: socket_udp_outgoing.cxx
// Created by: drose (01Mar07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "socket_udp_outgoing.h"
TypeHandle Socket_UDP_Outgoing::_type_handle;

View File

@ -15,7 +15,7 @@ PUBLISHED:
inline Socket_UDP_Outgoing() { }
// use this interface for a tagreted UDP connection
inline bool InitToAddress(Socket_Address & address);
inline bool InitToAddress(const Socket_Address & address);
public:
inline bool Send(const char * data, int len);
PUBLISHED:
@ -27,6 +27,23 @@ public:
PUBLISHED:
inline bool SendTo(const string &data, const Socket_Address & address);
inline bool SetToBroadCast();
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
Socket_IP::init_type();
register_type(_type_handle, "Socket_UDP_Outgoing",
Socket_IP::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
//////////////////////////////////////////////////////////////
// Function name : Socket_UDP_Outgoing:SetToBroadCast
@ -49,7 +66,7 @@ inline bool Socket_UDP_Outgoing::SetToBroadCast()
// Return type : inline bool
// Argument : NetAddress & address
////////////////////////////////////////////////////////////////////
inline bool Socket_UDP_Outgoing::InitToAddress(Socket_Address & address)
inline bool Socket_UDP_Outgoing::InitToAddress(const Socket_Address & address)
{
if (InitNoAddress() != true)
return false;

View File

@ -1,13 +1,13 @@
#define OTHER_LIBS \
interrogatedb:c dconfig:c dtoolconfig:m \
dtoolutil:c dtoolbase:c prc:c dtool:m
#define BUILD_DIRECTORY $[and $[HAVE_NET],$[HAVE_NSPR]]
#define USE_PACKAGES net nspr
#define BUILD_DIRECTORY $[and $[HAVE_NET],$[WANT_NATIVE_NET]]
#define USE_PACKAGES net
#begin lib_target
#define TARGET net
#define LOCAL_LIBS \
express pandabase
express pandabase nativenet pipeline
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
@ -18,7 +18,7 @@
datagramTCPHeader.I datagramTCPHeader.h \
datagramUDPHeader.I datagramUDPHeader.h \
netAddress.h netDatagram.I netDatagram.h \
pprerror.h queuedConnectionListener.I \
queuedConnectionListener.I \
queuedConnectionListener.h queuedConnectionManager.h \
queuedConnectionReader.h recentConnectionReader.h \
queuedReturn.h queuedReturn.I
@ -28,7 +28,7 @@
connectionManager.cxx connectionReader.cxx \
connectionWriter.cxx datagramQueue.cxx datagramTCPHeader.cxx \
datagramUDPHeader.cxx netAddress.cxx netDatagram.cxx \
pprerror.cxx queuedConnectionListener.cxx \
queuedConnectionListener.cxx \
queuedConnectionManager.cxx queuedConnectionReader.cxx \
recentConnectionReader.cxx
@ -38,7 +38,7 @@
datagramTCPHeader.I datagramTCPHeader.h \
datagramUDPHeader.I datagramUDPHeader.h \
netAddress.h netDatagram.I \
netDatagram.h pprerror.h queuedConnectionListener.I \
netDatagram.h queuedConnectionListener.I \
queuedConnectionListener.h queuedConnectionManager.h \
queuedConnectionReader.h queuedReturn.I queuedReturn.h \
recentConnectionReader.h
@ -59,7 +59,7 @@
#begin test_bin_target
#define TARGET test_spam_client
#define LOCAL_LIBS net
#define LOCAL_LIBS net putil
#define OTHER_LIBS $[OTHER_LIBS] pystub
#define SOURCES \
@ -69,7 +69,7 @@
#begin test_bin_target
#define TARGET test_spam_server
#define LOCAL_LIBS net
#define LOCAL_LIBS net putil
#define OTHER_LIBS $[OTHER_LIBS] pystub
#define SOURCES \

View File

@ -21,11 +21,15 @@
#include "netDatagram.h"
#include "datagramTCPHeader.h"
#include "datagramUDPHeader.h"
#include "pprerror.h"
#include "config_net.h"
#include "config_express.h" // for collect_tcp
#include "trueClock.h"
#include "pnotify.h"
#include "mutexHolder.h"
#include "socket_ip.h"
#include "socket_tcp.h"
#include "socket_udp.h"
#include "dcast.h"
////////////////////////////////////////////////////////////////////
@ -37,11 +41,10 @@
// connection.
////////////////////////////////////////////////////////////////////
Connection::
Connection(ConnectionManager *manager, PRFileDesc *socket) :
Connection(ConnectionManager *manager, Socket_IP *socket) :
_manager(manager),
_socket(socket)
{
_write_mutex = PR_NewLock();
_collect_tcp = collect_tcp;
_collect_tcp_interval = collect_tcp_interval;
_queued_data_start = 0.0;
@ -58,16 +61,12 @@ Connection::
net_cat.info()
<< "Deleting connection " << (void *)this << "\n";
if (_socket != (PRFileDesc *)NULL) {
if (_socket != (Socket_IP *)NULL) {
flush();
PRStatus result = PR_Close(_socket);
if (result != PR_SUCCESS) {
pprerror("PR_Close");
}
_socket->Close();
delete _socket;
}
PR_DestroyLock(_write_mutex);
}
////////////////////////////////////////////////////////////////////
@ -78,11 +77,7 @@ Connection::
////////////////////////////////////////////////////////////////////
NetAddress Connection::
get_address() const {
PRNetAddr addr;
if (PR_GetSockName(_socket, &addr) != PR_SUCCESS) {
pprerror("PR_GetSockName");
}
Socket_Address addr = _socket->GetPeerName();
return NetAddress(addr);
}
@ -100,10 +95,10 @@ get_manager() const {
////////////////////////////////////////////////////////////////////
// Function: Connection::get_socket
// Access: Published
// Description: Returns the internal NSPR pointer that defines the
// Description: Returns the internal Socket_IP that defines the
// connection.
////////////////////////////////////////////////////////////////////
PRFileDesc *Connection::
Socket_IP *Connection::
get_socket() const {
return _socket;
}
@ -182,7 +177,7 @@ get_collect_tcp_interval() const {
////////////////////////////////////////////////////////////////////
bool Connection::
consider_flush() {
PR_Lock(_write_mutex);
MutexHolder holder(_write_mutex);
if (!_collect_tcp) {
return do_flush();
@ -197,7 +192,6 @@ consider_flush() {
}
}
PR_Unlock(_write_mutex);
return true;
}
@ -210,7 +204,7 @@ consider_flush() {
////////////////////////////////////////////////////////////////////
bool Connection::
flush() {
PR_Lock(_write_mutex);
MutexHolder holder(_write_mutex);
return do_flush();
}
@ -221,10 +215,11 @@ flush() {
////////////////////////////////////////////////////////////////////
void Connection::
set_nonblock(bool flag) {
PRSocketOptionData data;
data.option = PR_SockOpt_Nonblocking;
data.value.non_blocking = flag;
PR_SetSocketOption(_socket, &data);
if (flag) {
_socket->SetNonBlocking();
} else {
_socket->SetBlocking();
}
}
////////////////////////////////////////////////////////////////////
@ -241,11 +236,14 @@ set_nonblock(bool flag) {
////////////////////////////////////////////////////////////////////
void Connection::
set_linger(bool flag, double time) {
PRSocketOptionData data;
data.option = PR_SockOpt_Linger;
data.value.linger.polarity = flag;
data.value.linger.linger = PRIntervalTime(time * PR_INTERVAL_MIN);
PR_SetSocketOption(_socket, &data);
Socket_TCP *tcp;
DCAST_INTO_V(tcp, _socket);
if (flag) {
tcp->SetLinger((int)time);
} else {
tcp->DontLinger();
}
}
////////////////////////////////////////////////////////////////////
@ -255,10 +253,7 @@ set_linger(bool flag, double time) {
////////////////////////////////////////////////////////////////////
void Connection::
set_reuse_addr(bool flag) {
PRSocketOptionData data;
data.option = PR_SockOpt_Reuseaddr;
data.value.reuse_addr = flag;
PR_SetSocketOption(_socket, &data);
_socket->SetReuseAddress(flag);
}
////////////////////////////////////////////////////////////////////
@ -269,10 +264,7 @@ set_reuse_addr(bool flag) {
////////////////////////////////////////////////////////////////////
void Connection::
set_keep_alive(bool flag) {
PRSocketOptionData data;
data.option = PR_SockOpt_Keepalive;
data.value.keep_alive = flag;
PR_SetSocketOption(_socket, &data);
// TODO.
}
////////////////////////////////////////////////////////////////////
@ -282,10 +274,7 @@ set_keep_alive(bool flag) {
////////////////////////////////////////////////////////////////////
void Connection::
set_recv_buffer_size(int size) {
PRSocketOptionData data;
data.option = PR_SockOpt_RecvBufferSize;
data.value.recv_buffer_size = size;
PR_SetSocketOption(_socket, &data);
_socket->SetRecvBufferSize(size);
}
////////////////////////////////////////////////////////////////////
@ -295,10 +284,10 @@ set_recv_buffer_size(int size) {
////////////////////////////////////////////////////////////////////
void Connection::
set_send_buffer_size(int size) {
PRSocketOptionData data;
data.option = PR_SockOpt_SendBufferSize;
data.value.send_buffer_size = size;
PR_SetSocketOption(_socket, &data);
Socket_TCP *tcp;
DCAST_INTO_V(tcp, _socket);
tcp->SetSendBufferSize(size);
}
////////////////////////////////////////////////////////////////////
@ -308,10 +297,7 @@ set_send_buffer_size(int size) {
////////////////////////////////////////////////////////////////////
void Connection::
set_ip_time_to_live(int ttl) {
PRSocketOptionData data;
data.option = PR_SockOpt_IpTimeToLive;
data.value.ip_ttl = ttl;
PR_SetSocketOption(_socket, &data);
// TODO.
}
////////////////////////////////////////////////////////////////////
@ -321,10 +307,7 @@ set_ip_time_to_live(int ttl) {
////////////////////////////////////////////////////////////////////
void Connection::
set_ip_type_of_service(int tos) {
PRSocketOptionData data;
data.option = PR_SockOpt_IpTypeOfService;
data.value.tos = tos;
PR_SetSocketOption(_socket, &data);
// TODO.
}
////////////////////////////////////////////////////////////////////
@ -335,10 +318,10 @@ set_ip_type_of_service(int tos) {
////////////////////////////////////////////////////////////////////
void Connection::
set_no_delay(bool flag) {
PRSocketOptionData data;
data.option = PR_SockOpt_NoDelay;
data.value.no_delay = flag;
PR_SetSocketOption(_socket, &data);
Socket_TCP *tcp;
DCAST_INTO_V(tcp, _socket);
tcp->SetNoDelay(flag);
}
////////////////////////////////////////////////////////////////////
@ -348,10 +331,7 @@ set_no_delay(bool flag) {
////////////////////////////////////////////////////////////////////
void Connection::
set_max_segment(int size) {
PRSocketOptionData data;
data.option = PR_SockOpt_MaxSegment;
data.value.max_segment = size;
PR_SetSocketOption(_socket, &data);
// TODO.
}
////////////////////////////////////////////////////////////////////
@ -365,37 +345,34 @@ set_max_segment(int size) {
////////////////////////////////////////////////////////////////////
bool Connection::
send_datagram(const NetDatagram &datagram, int tcp_header_size) {
nassertr(_socket != (PRFileDesc *)NULL, false);
nassertr(_socket != (Socket_IP *)NULL, false);
if (PR_GetDescType(_socket) == PR_DESC_SOCKET_UDP) {
if (_socket->is_exact_type(Socket_UDP::get_class_type())) {
// We have to send UDP right away.
PR_Lock(_write_mutex);
Socket_UDP *udp;
DCAST_INTO_R(udp, _socket, false);
MutexHolder holder(_write_mutex);
DatagramUDPHeader header(datagram);
string data;
data += header.get_header();
data += datagram.get_message();
PRInt32 bytes_to_send = data.length();
PRInt32 result;
result = PR_SendTo(_socket,
data.data(), bytes_to_send,
0,
datagram.get_address().get_addr(),
PR_INTERVAL_NO_TIMEOUT);
PRErrorCode errcode = PR_GetError();
int bytes_to_send = data.length();
bool okflag = udp->SendTo(data, datagram.get_address().get_addr());
if (net_cat.is_debug()) {
header.verify_datagram(datagram);
}
if (net_cat.is_spam()) {
net_cat.spam()
<< "Sending UDP datagram with "
<< bytes_to_send << " bytes to " << (void *)this << "\n";
<< bytes_to_send << " bytes to " << (void *)this
<< ", ok = " << okflag << "\n";
}
PR_Unlock(_write_mutex);
return check_send_error(result, errcode, bytes_to_send);
return check_send_error(okflag);
}
// We might queue up TCP packets for later sending.
@ -409,7 +386,7 @@ send_datagram(const NetDatagram &datagram, int tcp_header_size) {
DatagramTCPHeader header(datagram, tcp_header_size);
PR_Lock(_write_mutex);
MutexHolder holder(_write_mutex);
_queued_data += header.get_header();
_queued_data += datagram.get_message();
_queued_count++;
@ -423,7 +400,6 @@ send_datagram(const NetDatagram &datagram, int tcp_header_size) {
return do_flush();
}
PR_Unlock(_write_mutex);
return true;
}
@ -436,36 +412,30 @@ send_datagram(const NetDatagram &datagram, int tcp_header_size) {
////////////////////////////////////////////////////////////////////
bool Connection::
send_raw_datagram(const NetDatagram &datagram) {
nassertr(_socket != (PRFileDesc *)NULL, false);
nassertr(_socket != (Socket_IP *)NULL, false);
if (PR_GetDescType(_socket) == PR_DESC_SOCKET_UDP) {
if (_socket->is_exact_type(Socket_UDP::get_class_type())) {
// We have to send UDP right away.
Socket_UDP *udp;
DCAST_INTO_R(udp, _socket, false);
string data = datagram.get_message();
PRInt32 bytes_to_send = data.length();
MutexHolder holder(_write_mutex);
bool okflag = udp->SendTo(data, datagram.get_address().get_addr());
if (net_cat.is_spam()) {
net_cat.spam()
<< "Sending UDP datagram with "
<< bytes_to_send << " bytes to " << (void *)this << "\n";
<< data.size() << " bytes to " << (void *)this
<< ", ok = " << okflag << "\n";
}
PR_Lock(_write_mutex);
PRInt32 result;
result = PR_SendTo(_socket,
data.data(), bytes_to_send,
0,
datagram.get_address().get_addr(),
PR_INTERVAL_NO_TIMEOUT);
PRErrorCode errcode = PR_GetError();
PR_Unlock(_write_mutex);
return check_send_error(result, errcode, bytes_to_send);
return check_send_error(okflag);
}
// We might queue up TCP packets for later sending.
PR_Lock(_write_mutex);
MutexHolder holder(_write_mutex);
_queued_data += datagram.get_message();
_queued_count++;
@ -474,7 +444,6 @@ send_raw_datagram(const NetDatagram &datagram) {
return do_flush();
}
PR_Unlock(_write_mutex);
return true;
}
@ -482,70 +451,48 @@ send_raw_datagram(const NetDatagram &datagram) {
// Function: Connection::do_flush
// Access: Private
// Description: The private implementation of flush(), this assumes
// the _write_mutex has already been locked on entry.
// It will be unlocked on return.
// the _write_mutex is already held.
////////////////////////////////////////////////////////////////////
bool Connection::
do_flush() {
PRInt32 bytes_to_send = _queued_data.length();
if (bytes_to_send == 0) {
if (_queued_data.empty()) {
_queued_count = 0;
_queued_data_start = TrueClock::get_global_ptr()->get_short_time();
PR_Unlock(_write_mutex);
return true;
}
if (net_cat.is_spam()) {
net_cat.spam()
<< "Sending " << _queued_count << " TCP datagram(s) with "
<< bytes_to_send << " total bytes to " << (void *)this << "\n";
<< _queued_data.length() << " total bytes to " << (void *)this << "\n";
}
PRInt32 result;
result = PR_Send(_socket,
_queued_data.data(), bytes_to_send,
0,
PR_INTERVAL_NO_TIMEOUT);
PRErrorCode errcode = PR_GetError();
Socket_TCP *tcp;
DCAST_INTO_R(tcp, _socket, false);
bool okflag = (tcp->SendData(_queued_data) == _queued_data.size());
_queued_data = string();
_queued_count = 0;
_queued_data_start = TrueClock::get_global_ptr()->get_short_time();
PR_Unlock(_write_mutex);
return check_send_error(result, errcode, bytes_to_send);
return check_send_error(okflag);
}
////////////////////////////////////////////////////////////////////
// Function: Connection::check_send_error
// Access: Private
// Description: Checks the return value of a PR_Send() or PR_SendTo()
// Description: Checks the return value of a Send() or SendTo()
// call.
////////////////////////////////////////////////////////////////////
bool Connection::
check_send_error(PRInt32 result, PRErrorCode errcode, PRInt32 bytes_to_send) {
if (result < 0) {
if (errcode == PR_CONNECT_RESET_ERROR
#ifdef PR_SOCKET_SHUTDOWN_ERROR
|| errcode == PR_SOCKET_SHUTDOWN_ERROR
|| errcode == PR_CONNECT_ABORTED_ERROR
#endif
) {
// The connection has been reset; tell our manager about it
// and ignore it.
if (_manager != (ConnectionManager *)NULL) {
_manager->connection_reset(this, errcode);
}
} else if (errcode != PR_PENDING_INTERRUPT_ERROR) {
pprerror("PR_SendTo");
check_send_error(bool okflag) {
if (!okflag) {
// Assume any error means the connection has been reset; tell
// our manager about it and ignore it.
if (_manager != (ConnectionManager *)NULL) {
_manager->connection_reset(this, okflag);
}
return false;
} else if (result != bytes_to_send) {
net_cat.error() << "Not enough bytes sent to socket.\n";
return false;
}

View File

@ -22,11 +22,9 @@
#include "pandabase.h"
#include "referenceCount.h"
#include "netAddress.h"
#include "pmutex.h"
#include <prio.h>
#include <prlock.h>
#include <prerror.h>
class Socket_IP;
class ConnectionManager;
class NetDatagram;
@ -37,13 +35,13 @@ class NetDatagram;
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA Connection : public ReferenceCount {
PUBLISHED:
Connection(ConnectionManager *manager, PRFileDesc *socket);
Connection(ConnectionManager *manager, Socket_IP *socket);
~Connection();
NetAddress get_address() const;
ConnectionManager *get_manager() const;
PRFileDesc *get_socket() const;
Socket_IP *get_socket() const;
void set_collect_tcp(bool collect_tcp);
bool get_collect_tcp() const;
@ -69,11 +67,11 @@ private:
bool send_datagram(const NetDatagram &datagram, int tcp_header_size);
bool send_raw_datagram(const NetDatagram &datagram);
bool do_flush();
bool check_send_error(PRInt32 result, PRErrorCode errcode, PRInt32 bytes_to_send);
bool check_send_error(bool okflag);
ConnectionManager *_manager;
PRFileDesc *_socket;
PRLock *_write_mutex;
Socket_IP *_socket;
Mutex _write_mutex;
bool _collect_tcp;
double _collect_tcp_interval;

View File

@ -20,8 +20,8 @@
#include "connection.h"
#include "connectionManager.h"
#include "netAddress.h"
#include "pprerror.h"
#include "config_net.h"
#include "socket_tcp_listen.h"
////////////////////////////////////////////////////////////////////
// Function: ConnectionListener::Constructor
@ -56,13 +56,15 @@ receive_datagram(const NetDatagram &) {
////////////////////////////////////////////////////////////////////
void ConnectionListener::
process_incoming_data(SocketInfo *sinfo) {
PRNetAddr addr;
Socket_TCP_Listen *socket;
DCAST_INTO_V(socket, sinfo->get_socket());
PRFileDesc *socket =
PR_Accept(sinfo->get_socket(), &addr, PR_INTERVAL_NO_TIMEOUT);
if (socket == (PRFileDesc *)NULL) {
pprerror("PR_Accept");
Socket_Address addr;
Socket_TCP *session = new Socket_TCP;
if (!socket->GetIncomingConnection(*session, addr)) {
net_cat.error()
<< "Error when accepting new connection.\n";
delete session;
} else {
NetAddress net_addr(addr);
@ -71,7 +73,7 @@ process_incoming_data(SocketInfo *sinfo) {
<< " on port " << sinfo->_connection->get_address().get_port()
<< "\n";
PT(Connection) new_connection = new Connection(_manager, socket);
PT(Connection) new_connection = new Connection(_manager, session);
if (_manager != (ConnectionManager *)NULL) {
_manager->new_connection(new_connection);
}

View File

@ -21,10 +21,8 @@
#include "connectionReader.h"
#include "connectionWriter.h"
#include "netAddress.h"
#include "pprerror.h"
#include "config_net.h"
#include <prerror.h>
#include "mutexHolder.h"
#ifdef WIN32_VC
#include <winsock.h> // For gethostname()
@ -37,7 +35,6 @@
////////////////////////////////////////////////////////////////////
ConnectionManager::
ConnectionManager() {
_set_mutex = PR_NewLock();
}
////////////////////////////////////////////////////////////////////
@ -56,8 +53,6 @@ ConnectionManager::
for (wi = _writers.begin(); wi != _writers.end(); ++wi) {
(*wi)->clear_manager();
}
PR_DestroyLock(_set_mutex);
}
@ -65,41 +60,42 @@ ConnectionManager::
// Function: ConnectionManager::open_UDP_connection
// Access: Public
// Description: Opens a socket for sending and/or receiving UDP
// packets. If the port number is negative, it will not
// be bound to a socket; this is generally a pointless
// thing to do. If the port number is zero, a random
// socket will be chosen. Otherwise, the specified
// port number is used. Normally, you don't care what
// port a UDP connection is opened on, so you should use
// the default value of zero.
// packets. If the port number is greater than zero,
// the UDP connection will be opened for listening on
// the indicated port; otherwise, it will be useful only
// for sending.
//
// Use a ConnectionReader and ConnectionWriter to handle
// the actual communication.
////////////////////////////////////////////////////////////////////
PT(Connection) ConnectionManager::
open_UDP_connection(int port) {
NetAddress address;
address.set_any(port);
Socket_UDP *socket = new Socket_UDP;
PRFileDesc *socket = PR_NewUDPSocket();
if (socket == (PRFileDesc *)NULL) {
pprerror("PR_NewUDPSocket");
return PT(Connection)();
}
if (port >= 0) {
PRStatus result = PR_Bind(socket, address.get_addr());
if (result != PR_SUCCESS) {
pprerror("PR_Bind");
PR_Close(socket);
if (port > 0) {
NetAddress address;
address.set_any(port);
if (!socket->OpenForInput(address.get_addr())) {
net_cat.error()
<< "Unable to bind to port " << port << " for UDP.\n";
delete socket;
return PT(Connection)();
}
net_cat.info()
<< "Creating UDP connection for port " << port << "\n";
} else {
if (!socket->InitNoAddress()) {
net_cat.error()
<< "Unable to initialize outgoing UDP.\n";
delete socket;
return PT(Connection)();
}
net_cat.info()
<< "Creating UDP connection\n";
<< "Creating outgoing UDP connection\n";
}
PT(Connection) connection = new Connection(this, socket);
@ -125,27 +121,12 @@ open_TCP_server_rendezvous(int port, int backlog) {
NetAddress address;
address.set_any(port);
PRFileDesc *socket = PR_NewTCPSocket();
if (socket == (PRFileDesc *)NULL) {
pprerror("PR_NewTCPSocket");
return PT(Connection)();
}
PRStatus result = PR_Bind(socket, address.get_addr());
if (result != PR_SUCCESS) {
pprerror("PR_Bind");
net_cat.info()
<< "Unable to bind to port " << port << " for TCP.\n";
PR_Close(socket);
return PT(Connection)();
}
result = PR_Listen(socket, backlog);
if (result != PR_SUCCESS) {
pprerror("PR_Listen");
Socket_TCP_Listen *socket = new Socket_TCP_Listen;
bool okflag = socket->OpenForListen(address.get_addr(), backlog);
if (!okflag) {
net_cat.info()
<< "Unable to listen to port " << port << " for TCP.\n";
PR_Close(socket);
delete socket;
return PT(Connection)();
}
@ -167,22 +148,13 @@ open_TCP_server_rendezvous(int port, int backlog) {
////////////////////////////////////////////////////////////////////
PT(Connection) ConnectionManager::
open_TCP_client_connection(const NetAddress &address, int timeout_ms) {
PRFileDesc *socket = PR_NewTCPSocket();
if (socket == (PRFileDesc *)NULL) {
pprerror("PR_NewTCPSocket");
return PT(Connection)();
}
PRStatus result = PR_Connect(socket, address.get_addr(),
PR_MillisecondsToInterval(timeout_ms));
if (result != PR_SUCCESS) {
if (PR_GetError() != PR_CONNECT_RESET_ERROR) {
pprerror("PR_Connect");
}
net_cat.info()
Socket_TCP *socket = new Socket_TCP;
bool okflag = socket->ActiveOpen(address.get_addr());
if (!okflag) {
net_cat.error()
<< "Unable to open TCP connection to server "
<< address.get_ip_string() << " on port " << address.get_port() << "\n";
PR_Close(socket);
delete socket;
return PT(Connection)();
}
@ -199,7 +171,7 @@ open_TCP_client_connection(const NetAddress &address, int timeout_ms) {
// Function: ConnectionManager::open_TCP_client_connection
// Access: Public
// Description: This is a shorthand version of the function to
// directly establish communcations to a named host and
// directly establish communications to a named host and
// port.
////////////////////////////////////////////////////////////////////
PT(Connection) ConnectionManager::
@ -238,42 +210,33 @@ close_connection(const PT(Connection) &connection) {
connection->flush();
}
PR_Lock(_set_mutex);
Connections::iterator ci = _connections.find(connection);
if (ci == _connections.end()) {
// Already closed, or not part of this ConnectionManager.
PR_Unlock(_set_mutex);
return false;
}
_connections.erase(ci);
Readers::iterator ri;
for (ri = _readers.begin(); ri != _readers.end(); ++ri) {
(*ri)->remove_connection(connection);
}
PR_Unlock(_set_mutex);
PRFileDesc *socket = connection->get_socket();
if (PR_GetDescType(socket) == PR_DESC_SOCKET_TCP) {
// We can't *actually* close the connection right now, because
// there might be outstanding pointers to it. But we can at least
// shut it down. It will be eventually closed when all the
// pointers let go.
net_cat.info()
<< "Shutting down connection " << (void *)connection
<< " locally.\n";
PRStatus result = PR_Shutdown(socket, PR_SHUTDOWN_BOTH);
if (result != PR_SUCCESS) {
PRErrorCode errcode = PR_GetError();
if (errcode != PR_NOT_CONNECTED_ERROR) {
pprerror("PR_Shutdown");
}
{
MutexHolder holder(_set_mutex);
Connections::iterator ci = _connections.find(connection);
if (ci == _connections.end()) {
// Already closed, or not part of this ConnectionManager.
return false;
}
_connections.erase(ci);
Readers::iterator ri;
for (ri = _readers.begin(); ri != _readers.end(); ++ri) {
(*ri)->remove_connection(connection);
}
}
Socket_IP *socket = connection->get_socket();
// We can't *actually* close the connection right now, because
// there might be outstanding pointers to it. But we can at least
// shut it down. It will be eventually closed when all the
// pointers let go.
net_cat.info()
<< "Shutting down connection " << (void *)connection
<< " locally.\n";
socket->Close();
return true;
}
@ -305,9 +268,8 @@ get_host_name() {
////////////////////////////////////////////////////////////////////
void ConnectionManager::
new_connection(const PT(Connection) &connection) {
PR_Lock(_set_mutex);
MutexHolder holder(_set_mutex);
_connections.insert(connection);
PR_Unlock(_set_mutex);
}
////////////////////////////////////////////////////////////////////
@ -320,9 +282,9 @@ new_connection(const PT(Connection) &connection) {
// been reset.
////////////////////////////////////////////////////////////////////
void ConnectionManager::
connection_reset(const PT(Connection) &connection, PRErrorCode errcode) {
connection_reset(const PT(Connection) &connection, bool okflag) {
if (net_cat.is_info()) {
if (errcode == 0) {
if (okflag) {
net_cat.info()
<< "Connection " << (void *)connection
<< " was closed normally by the other end";
@ -330,33 +292,8 @@ connection_reset(const PT(Connection) &connection, PRErrorCode errcode) {
} else {
net_cat.info()
<< "Lost connection " << (void *)connection
<< " unexpectedly: ";
switch (errcode) {
case PR_CONNECT_RESET_ERROR:
net_cat.info(false)
<< "connection reset";
break;
#ifdef PR_SOCKET_SHUTDOWN_ERROR
case PR_SOCKET_SHUTDOWN_ERROR:
net_cat.info(false)
<< "socket shutdown";
break;
case PR_CONNECT_ABORTED_ERROR:
net_cat.info(false)
<< "connection aborted";
break;
#endif
default:
net_cat.info(false)
<< "NSPR error code " << errcode;
}
<< " unexpectedly\n";
}
net_cat.info(false)
<< " (os error = " << PR_GetOSError() << ").\n";
}
// Turns out we do need to explicitly mark the connection as closed
@ -374,9 +311,8 @@ connection_reset(const PT(Connection) &connection, PRErrorCode errcode) {
////////////////////////////////////////////////////////////////////
void ConnectionManager::
add_reader(ConnectionReader *reader) {
PR_Lock(_set_mutex);
MutexHolder holder(_set_mutex);
_readers.insert(reader);
PR_Unlock(_set_mutex);
}
////////////////////////////////////////////////////////////////////
@ -387,9 +323,8 @@ add_reader(ConnectionReader *reader) {
////////////////////////////////////////////////////////////////////
void ConnectionManager::
remove_reader(ConnectionReader *reader) {
PR_Lock(_set_mutex);
MutexHolder holder(_set_mutex);
_readers.erase(reader);
PR_Unlock(_set_mutex);
}
////////////////////////////////////////////////////////////////////
@ -400,9 +335,8 @@ remove_reader(ConnectionReader *reader) {
////////////////////////////////////////////////////////////////////
void ConnectionManager::
add_writer(ConnectionWriter *writer) {
PR_Lock(_set_mutex);
MutexHolder holder(_set_mutex);
_writers.insert(writer);
PR_Unlock(_set_mutex);
}
////////////////////////////////////////////////////////////////////
@ -413,7 +347,6 @@ add_writer(ConnectionWriter *writer) {
////////////////////////////////////////////////////////////////////
void ConnectionManager::
remove_writer(ConnectionWriter *writer) {
PR_Lock(_set_mutex);
MutexHolder holder(_set_mutex);
_writers.erase(writer);
PR_Unlock(_set_mutex);
}

View File

@ -25,9 +25,7 @@
#include "connection.h"
#include "pointerTo.h"
#include "pset.h"
#include <prlock.h>
#include <prerror.h>
#include "pmutex.h"
class NetAddress;
class ConnectionReader;
@ -69,7 +67,7 @@ PUBLISHED:
protected:
void new_connection(const PT(Connection) &connection);
virtual void connection_reset(const PT(Connection) &connection,
PRErrorCode errcode);
bool okflag);
void add_reader(ConnectionReader *reader);
void remove_reader(ConnectionReader *reader);
@ -82,7 +80,7 @@ protected:
Connections _connections;
Readers _readers;
Writers _writers;
PRLock *_set_mutex;
Mutex _set_mutex;
private:
friend class ConnectionReader;

View File

@ -21,20 +21,17 @@
#include "netDatagram.h"
#include "datagramTCPHeader.h"
#include "datagramUDPHeader.h"
#include "pprerror.h"
#include "config_net.h"
#include "trueClock.h"
#include "socket_udp.h"
#include "socket_tcp.h"
#include "mutexHolder.h"
#include "pnotify.h"
#include <prerror.h>
#include <pratom.h>
#include <algorithm>
#include "atomicAdjust.h"
static const int read_buffer_size = maximum_udp_datagram + datagram_udp_header_size;
// We have to impose a maximum timeout on the PR_Poll() call because
// PR_Poll() doesn't seem to be interruptible! (!)
static const PRUint32 max_timeout_ms = 100;
static const int max_timeout_ms = 100;
////////////////////////////////////////////////////////////////////
// Function: ConnectionReader::SocketInfo::Constructor
@ -56,7 +53,7 @@ SocketInfo(const PT(Connection) &connection) :
////////////////////////////////////////////////////////////////////
bool ConnectionReader::SocketInfo::
is_udp() const {
return (PR_GetDescType(_connection->get_socket()) == PR_DESC_SOCKET_UDP);
return (_connection->get_socket()->is_exact_type(Socket_UDP::get_class_type()));
}
////////////////////////////////////////////////////////////////////
@ -64,11 +61,34 @@ is_udp() const {
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
PRFileDesc *ConnectionReader::SocketInfo::
Socket_IP *ConnectionReader::SocketInfo::
get_socket() const {
return _connection->get_socket();
}
////////////////////////////////////////////////////////////////////
// Function: ConnectionReader::ReaderThread::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
ConnectionReader::ReaderThread::
ReaderThread(ConnectionReader *reader, int thread_index) :
Thread("ReaderThread", "ReaderThread"),
_reader(reader),
_thread_index(thread_index)
{
}
////////////////////////////////////////////////////////////////////
// Function: ConnectionReader::ReaderThread::thread_main
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void ConnectionReader::ReaderThread::
thread_main() {
_reader->thread_run(_thread_index);
}
////////////////////////////////////////////////////////////////////
// Function: ConnectionReader::Constructor
// Access: Public
@ -83,10 +103,6 @@ ConnectionReader(ConnectionManager *manager, int num_threads) :
_manager(manager)
{
#ifndef HAVE_THREADS
// Although this code is written to use thread-locking primitives
// regardless of the definition of HAVE_THREADS, it is not safe to
// spawn multiple threads when HAVE_THREADS is not true, since we
// might be using a non-thread-safe malloc scheme.
#ifndef NDEBUG
if (num_threads != 0) {
net_cat.error()
@ -101,36 +117,20 @@ ConnectionReader(ConnectionManager *manager, int num_threads) :
_polling = (num_threads <= 0);
_shutdown = false;
_startup_mutex = PR_NewLock();
_next_index = 0;
_num_results = 0;
_select_mutex = PR_NewLock();
_currently_polling_thread = -1;
_reexamine_sockets = false;
_sockets_mutex = PR_NewLock();
// Before we create all the threads, grab _startup_mutex. That will
// prevent our new threads from trying to look themselves up in the
// _threads array before we have filled it up.
PR_Lock(_startup_mutex);
for (int i = 0; i < num_threads; i++) {
PRThread *thread =
PR_CreateThread(PR_USER_THREAD,
thread_start, (void *)this,
PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD, // Since thread will mostly do I/O.
PR_JOINABLE_THREAD,
0); // Select a suitable stack size.
nassertv(thread != (PRThread *)NULL);
int i;
for (i = 0; i < num_threads; i++) {
PT(ReaderThread) thread = new ReaderThread(this, i);
_threads.push_back(thread);
}
PR_Unlock(_startup_mutex);
for (i = 0; i < num_threads; i++) {
_threads[i]->start(TP_normal, true, true);
}
_manager->add_reader(this);
}
@ -166,10 +166,6 @@ ConnectionReader::
sinfo->_connection.clear();
}
}
PR_DestroyLock(_startup_mutex);
PR_DestroyLock(_select_mutex);
PR_DestroyLock(_sockets_mutex);
}
////////////////////////////////////////////////////////////////////
@ -190,24 +186,21 @@ ConnectionReader::
// will by any thread.
////////////////////////////////////////////////////////////////////
bool ConnectionReader::
add_connection(const PT(Connection) &connection) {
add_connection(Connection *connection) {
nassertr(connection != (Connection *)NULL, false);
PR_Lock(_sockets_mutex);
MutexHolder holder(_sockets_mutex);
// Make sure it's not already on the _sockets list.
Sockets::const_iterator si;
for (si = _sockets.begin(); si != _sockets.end(); ++si) {
if ((*si)->_connection == connection) {
// Whoops, already there.
PR_Unlock(_sockets_mutex);
return false;
}
}
_sockets.push_back(new SocketInfo(connection));
_reexamine_sockets = true;
PR_Unlock(_sockets_mutex);
return true;
}
@ -224,8 +217,8 @@ add_connection(const PT(Connection) &connection) {
// at will by any thread.
////////////////////////////////////////////////////////////////////
bool ConnectionReader::
remove_connection(const PT(Connection) &connection) {
PR_Lock(_sockets_mutex);
remove_connection(Connection *connection) {
MutexHolder holder(_sockets_mutex);
// Walk through the list of sockets to find the one we're removing.
Sockets::iterator si;
@ -234,14 +227,11 @@ remove_connection(const PT(Connection) &connection) {
++si;
}
if (si == _sockets.end()) {
PR_Unlock(_sockets_mutex);
return false;
}
_removed_sockets.push_back(*si);
_sockets.erase(si);
_reexamine_sockets = true;
PR_Unlock(_sockets_mutex);
return true;
}
@ -258,8 +248,8 @@ remove_connection(const PT(Connection) &connection) {
// the connection.)
////////////////////////////////////////////////////////////////////
bool ConnectionReader::
is_connection_ok(const PT(Connection) &connection) {
PR_Lock(_sockets_mutex);
is_connection_ok(Connection *connection) {
MutexHolder holder(_sockets_mutex);
// Walk through the list of sockets to find the one we're asking
// about.
@ -270,13 +260,11 @@ is_connection_ok(const PT(Connection) &connection) {
}
if (si == _sockets.end()) {
// Don't know that connection.
PR_Unlock(_sockets_mutex);
return false;
}
SocketInfo *sinfo = (*si);
bool is_ok = !sinfo->_error;
PR_Unlock(_sockets_mutex);
return is_ok;
}
@ -299,14 +287,14 @@ poll() {
return;
}
SocketInfo *sinfo = get_next_available_socket(PR_INTERVAL_NO_WAIT, -2);
SocketInfo *sinfo = get_next_available_socket(false, -2);
if (sinfo != (SocketInfo *)NULL) {
double max_poll_cycle = get_max_poll_cycle();
if (max_poll_cycle < 0.0) {
// Continue to read all data.
while (sinfo != (SocketInfo *)NULL) {
process_incoming_data(sinfo);
sinfo = get_next_available_socket(PR_INTERVAL_NO_WAIT, -2);
sinfo = get_next_available_socket(false, -2);
}
} else {
@ -319,7 +307,7 @@ poll() {
if (global_clock->get_short_time() >= stop) {
return;
}
sinfo = get_next_available_socket(PR_INTERVAL_NO_WAIT, -2);
sinfo = get_next_available_socket(false, -2);
}
}
}
@ -429,16 +417,7 @@ shutdown() {
// Now wait for all of our threads to terminate.
Threads::iterator ti;
for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
// Interrupt the thread so it can notice the shutdown.
PRStatus result = PR_Interrupt(*ti);
if (result != PR_SUCCESS) {
pprerror("PR_Interrupt");
}
result = PR_JoinThread(*ti);
if (result != PR_SUCCESS) {
pprerror("PR_JoinThread");
}
(*ti)->join();
}
}
@ -470,34 +449,14 @@ finish_socket(SocketInfo *sinfo) {
// By marking the SocketInfo nonbusy, we make it available for
// future polls.
sinfo->_busy = false;
_reexamine_sockets = true;
// However, someone might be already blocking on an
// earlier-established PR_Poll() that doesn't involve this socket.
// That complicates things. It means we'll have to wake that thread
// up so it can rebuild the poll with the new socket.
// Actually, don't bother, since it turns out that PR_Poll() isn't
// interruptible anyway. Sigh. Maybe we'll revisit this later, but
// in the meantime it means we have to rig up the PR_Poll() to
// return every so often and check the _reexamine_sockets flag by
// itself.
/*
int thread = _currently_polling_thread;
if (thread != -1) {
nassertv(thread >= 0 && thread < _threads.size());
PR_Interrupt(_threads[thread]);
}
*/
}
////////////////////////////////////////////////////////////////////
// Function: ConnectionReader::process_incoming_data
// Access: Protected, Virtual
// Description: This is run within a thread when the call to
// PR_Poll() indicates there is data available
// on a socket.
// select() indicates there is data available on a
// socket.
////////////////////////////////////////////////////////////////////
void ConnectionReader::
process_incoming_data(SocketInfo *sinfo) {
@ -523,21 +482,17 @@ process_incoming_data(SocketInfo *sinfo) {
////////////////////////////////////////////////////////////////////
void ConnectionReader::
process_incoming_udp_data(SocketInfo *sinfo) {
PRFileDesc *socket = sinfo->get_socket();
PRNetAddr addr;
Socket_UDP *socket;
DCAST_INTO_V(socket, sinfo->get_socket());
Socket_Address addr;
// Read as many bytes as we can.
PRInt8 buffer[read_buffer_size];
PRInt32 bytes_read;
char buffer[read_buffer_size];
int bytes_read = read_buffer_size;
bytes_read = PR_RecvFrom(socket, buffer, read_buffer_size, 0,
&addr, PR_INTERVAL_NO_TIMEOUT);
bool okflag = socket->GetPacket(buffer, &bytes_read, addr);
if (bytes_read < 0) {
PRErrorCode errcode = PR_GetError();
if (errcode != PR_PENDING_INTERRUPT_ERROR) {
pprerror("PR_RecvFrom");
}
if (!okflag) {
finish_socket(sinfo);
return;
@ -563,7 +518,7 @@ process_incoming_udp_data(SocketInfo *sinfo) {
DatagramUDPHeader header(buffer);
PRInt8 *dp = buffer + datagram_udp_header_size;
char *dp = buffer + datagram_udp_header_size;
bytes_read -= datagram_udp_header_size;
NetDatagram datagram(dp, bytes_read);
@ -594,44 +549,20 @@ process_incoming_udp_data(SocketInfo *sinfo) {
////////////////////////////////////////////////////////////////////
void ConnectionReader::
process_incoming_tcp_data(SocketInfo *sinfo) {
PRFileDesc *socket = sinfo->get_socket();
PRNetAddr addr;
Socket_TCP *socket;
DCAST_INTO_V(socket, sinfo->get_socket());
// Read only the header bytes to start with.
PRInt8 buffer[read_buffer_size];
PRInt32 header_bytes_read = 0;
if (PR_GetSockName(socket, &addr) != PR_SUCCESS) {
pprerror("PR_GetSockName");
}
char buffer[read_buffer_size];
int header_bytes_read = 0;
// First, we have to read the first _tcp_header_size bytes.
while (header_bytes_read < _tcp_header_size) {
PRInt32 bytes_read =
PR_Recv(socket, buffer + header_bytes_read,
_tcp_header_size - header_bytes_read, 0,
PR_INTERVAL_NO_TIMEOUT);
int bytes_read =
socket->RecvData(buffer + header_bytes_read,
_tcp_header_size - header_bytes_read);
if (bytes_read < 0) {
PRErrorCode errcode = PR_GetError();
if (errcode == PR_CONNECT_RESET_ERROR
#ifdef PR_SOCKET_SHUTDOWN_ERROR
|| errcode == PR_SOCKET_SHUTDOWN_ERROR
|| errcode == PR_CONNECT_ABORTED_ERROR
#endif
) {
// The socket was closed.
if (_manager != (ConnectionManager *)NULL) {
_manager->connection_reset(sinfo->_connection, errcode);
}
} else if (errcode != PR_PENDING_INTERRUPT_ERROR) {
pprerror("PR_Recv");
}
finish_socket(sinfo);
return;
} else if (bytes_read == 0) {
if (bytes_read <= 0) {
// The socket was closed. Report that and return.
if (_manager != (ConnectionManager *)NULL) {
_manager->connection_reset(sinfo->_connection, 0);
@ -655,41 +586,20 @@ process_incoming_tcp_data(SocketInfo *sinfo) {
}
DatagramTCPHeader header(buffer, _tcp_header_size);
PRInt32 size = header.get_datagram_size(_tcp_header_size);
int size = header.get_datagram_size(_tcp_header_size);
// We have to loop until the entire datagram is read.
NetDatagram datagram;
while (!_shutdown && (int)datagram.get_length() < size) {
PRInt32 bytes_read;
int bytes_read;
bytes_read =
PR_Recv(socket, buffer,
min((PRInt32)read_buffer_size,
(PRInt32)(size - datagram.get_length())),
0, PR_INTERVAL_NO_TIMEOUT);
PRInt8 *dp = buffer;
socket->RecvData(buffer, min(read_buffer_size,
(int)(size - datagram.get_length())));
char *dp = buffer;
if (bytes_read < 0) {
PRErrorCode errcode = PR_GetError();
if (errcode == PR_CONNECT_RESET_ERROR
#ifdef PR_SOCKET_SHUTDOWN_ERROR
|| errcode == PR_SOCKET_SHUTDOWN_ERROR
|| errcode == PR_CONNECT_ABORTED_ERROR
#endif
) {
// The socket was closed.
if (_manager != (ConnectionManager *)NULL) {
_manager->connection_reset(sinfo->_connection, errcode);
}
} else if (errcode != PR_PENDING_INTERRUPT_ERROR) {
pprerror("PR_Recv");
}
finish_socket(sinfo);
return;
} else if (bytes_read == 0) {
if (bytes_read <= 0) {
// The socket was closed. Report that and return.
if (_manager != (ConnectionManager *)NULL) {
_manager->connection_reset(sinfo->_connection, 0);
@ -698,8 +608,8 @@ process_incoming_tcp_data(SocketInfo *sinfo) {
return;
}
PRInt32 datagram_bytes =
min(bytes_read, (PRInt32)(size - datagram.get_length()));
int datagram_bytes =
min(bytes_read, (int)(size - datagram.get_length()));
datagram.append_data(dp, datagram_bytes);
if (bytes_read > datagram_bytes) {
@ -725,7 +635,7 @@ process_incoming_tcp_data(SocketInfo *sinfo) {
<< "Ignoring invalid TCP datagram.\n";
} else {
datagram.set_connection(sinfo->_connection);
datagram.set_address(NetAddress(addr));
datagram.set_address(NetAddress(socket->GetPeerName()));
receive_datagram(datagram);
}
}
@ -737,21 +647,17 @@ process_incoming_tcp_data(SocketInfo *sinfo) {
////////////////////////////////////////////////////////////////////
void ConnectionReader::
process_raw_incoming_udp_data(SocketInfo *sinfo) {
PRFileDesc *socket = sinfo->get_socket();
PRNetAddr addr;
Socket_UDP *socket;
DCAST_INTO_V(socket, sinfo->get_socket());
Socket_Address addr;
// Read as many bytes as we can.
PRInt8 buffer[read_buffer_size];
PRInt32 bytes_read;
char buffer[read_buffer_size];
int bytes_read = read_buffer_size;
bytes_read = PR_RecvFrom(socket, buffer, read_buffer_size, 0,
&addr, PR_INTERVAL_NO_TIMEOUT);
bool okflag = socket->GetPacket(buffer, &bytes_read, addr);
if (bytes_read < 0) {
PRErrorCode errcode = PR_GetError();
if (errcode != PR_PENDING_INTERRUPT_ERROR) {
pprerror("PR_RecvFrom");
}
if (!okflag) {
finish_socket(sinfo);
return;
@ -789,29 +695,14 @@ process_raw_incoming_udp_data(SocketInfo *sinfo) {
////////////////////////////////////////////////////////////////////
void ConnectionReader::
process_raw_incoming_tcp_data(SocketInfo *sinfo) {
PRFileDesc *socket = sinfo->get_socket();
PRNetAddr addr;
Socket_TCP *socket;
DCAST_INTO_V(socket, sinfo->get_socket());
// Read as many bytes as we can.
PRInt8 buffer[read_buffer_size];
PRInt32 bytes_read;
char buffer[read_buffer_size];
int bytes_read = socket->RecvData(buffer, read_buffer_size);
if (PR_GetSockName(socket, &addr) != PR_SUCCESS) {
pprerror("PR_GetSockName");
}
bytes_read = PR_Recv(socket, buffer, read_buffer_size, 0,
PR_INTERVAL_NO_TIMEOUT);
if (bytes_read < 0) {
PRErrorCode errcode = PR_GetError();
if (errcode != PR_PENDING_INTERRUPT_ERROR) {
pprerror("PR_RecvFrom");
}
finish_socket(sinfo);
return;
} else if (bytes_read == 0) {
if (bytes_read <= 0) {
// The socket was closed. Report that and return.
if (_manager != (ConnectionManager *)NULL) {
_manager->connection_reset(sinfo->_connection, 0);
@ -833,24 +724,10 @@ process_raw_incoming_tcp_data(SocketInfo *sinfo) {
}
datagram.set_connection(sinfo->_connection);
datagram.set_address(NetAddress(addr));
datagram.set_address(NetAddress(socket->GetPeerName()));
receive_datagram(datagram);
}
////////////////////////////////////////////////////////////////////
// Function: ConnectionReader::thread_start
// Access: Private, Static
// Description: The static wrapper around the thread's executing
// function. This must be a static member function
// because it is passed through the C interface to
// PR_CreateThread().
////////////////////////////////////////////////////////////////////
void ConnectionReader::
thread_start(void *data) {
((ConnectionReader *)data)->thread_run();
}
////////////////////////////////////////////////////////////////////
// Function: ConnectionReader::thread_run
// Access: Private
@ -858,24 +735,13 @@ thread_start(void *data) {
// thread.
////////////////////////////////////////////////////////////////////
void ConnectionReader::
thread_run() {
thread_run(int thread_index) {
nassertv(!_polling);
// First determine our own thread index.
PR_Lock(_startup_mutex);
Threads::const_iterator ti =
find(_threads.begin(), _threads.end(), PR_GetCurrentThread());
nassertv(ti != _threads.end());
PRInt32 current_thread_index = (ti - _threads.begin());
nassertv(_threads[current_thread_index] == PR_GetCurrentThread());
PR_Unlock(_startup_mutex);
nassertv(_threads[thread_index] == Thread::get_current_thread());
while (!_shutdown) {
SocketInfo *sinfo =
get_next_available_socket(PR_INTERVAL_NO_TIMEOUT,
current_thread_index);
get_next_available_socket(false, thread_index);
if (sinfo != (SocketInfo *)NULL) {
process_incoming_data(sinfo);
}
@ -892,59 +758,29 @@ thread_run() {
//
// This function may block indefinitely if it is being
// called by multiple threads; if there are no other
// threads, it may block only if timeout !=
// PR_INTERVAL_NO_WAIT.
// threads, it may block only if allow_block is true.
////////////////////////////////////////////////////////////////////
ConnectionReader::SocketInfo *ConnectionReader::
get_next_available_socket(PRIntervalTime timeout,
PRInt32 current_thread_index) {
get_next_available_socket(bool allow_block, int current_thread_index) {
// Go to sleep on the select() mutex. This guarantees that only one
// thread is in this function at a time.
PR_Lock(_select_mutex);
int num_sockets = _polled_sockets.size();
nassertr(num_sockets == (int)_poll.size(), NULL);
MutexHolder holder(_select_mutex);
do {
// First, check the result from the previous PR_Poll() call. If
// First, check the result from the previous select call. If
// there are any sockets remaining there, process them first.
while (!_shutdown && _num_results > 0) {
nassertr(_next_index < num_sockets, NULL);
nassertr(_next_index < (int)_selecting_sockets.size(), NULL);
int i = _next_index;
_next_index++;
if (_poll[i].out_flags != 0) {
if (_fdset.IsSetFor(*_selecting_sockets[i]->get_socket())) {
_num_results--;
SocketInfo *sinfo = _polled_sockets[i];
SocketInfo *sinfo = _selecting_sockets[i];
if ((_poll[i].out_flags & PR_POLL_READ) != 0) {
// Some genuine noise on the port.
sinfo->_busy = true;
_reexamine_sockets = true;
PR_Unlock(_select_mutex);
PR_Sleep(PR_INTERVAL_NO_WAIT);
return sinfo;
} else if ((_poll[i].out_flags &
(PR_POLL_ERR | PR_POLL_NVAL | PR_POLL_HUP)) != 0) {
// Something bad happened to this socket. Tell the
// ConnectionManager to drop it.
if (_manager != (ConnectionManager *)NULL) {
// Perform a recv to force an error code.
char buffer[1];
PRInt32 got_bytes =
PR_Recv(sinfo->get_socket(), buffer, 1, 0, PR_INTERVAL_NO_WAIT);
if (got_bytes > 0) {
net_cat.error()
<< "poll returned error flags " << hex << _poll[i].out_flags
<< dec << " but read " << got_bytes << " from socket.\n";
}
PRErrorCode errcode = PR_GetError();
_manager->connection_reset(sinfo->_connection, errcode);
}
sinfo->_error = true;
_reexamine_sockets = true;
}
// Some noise on this socket.
sinfo->_busy = true;
return sinfo;
}
}
@ -952,93 +788,70 @@ get_next_available_socket(PRIntervalTime timeout,
do {
interrupted = false;
// Ok, no results from previous PR_Poll() calls. Prepare to set
// up for a new poll.
// Ok, no results from previous select calls. Prepare to set up
// for a new select.
// First, report to anyone else who cares that we're the thread
// about to do the poll. That way, if any new sockets come
// available while we're polling, we can service them.
PR_AtomicSet(&_currently_polling_thread, current_thread_index);
AtomicAdjust::set(_currently_polling_thread, current_thread_index);
rebuild_select_list();
if (_reexamine_sockets) {
_reexamine_sockets = false;
rebuild_poll_list();
num_sockets = _polled_sockets.size();
nassertr(num_sockets == (int)_poll.size(), NULL);
}
// Now we can execute PR_Poll(). This basically maps to a Unix
// select() call.
// Now we can execute the select.
_num_results = 0;
_next_index = 0;
if (!_shutdown) {
PRIntervalTime poll_timeout =
PR_MillisecondsToInterval(max_timeout_ms);
if (timeout != PR_INTERVAL_NO_TIMEOUT) {
poll_timeout = min(timeout, poll_timeout);
PN_uint32 timeout = max_timeout_ms;
if (!allow_block) {
timeout = 0;
}
_num_results = PR_Poll(&_poll[0], num_sockets, poll_timeout);
_num_results = _fdset.WaitForRead(false, timeout);
}
if (_num_results == 0 && timeout == PR_INTERVAL_NO_TIMEOUT) {
// If we reached max_timeout_ms, but the caller didn't request
// a timeout, consider that an interrupt: go back and
// reconsider. (This is a kludge around the fact that
// PR_Poll() appears to be non-interruptible.)
if (_num_results == 0 && allow_block) {
// If we reached max_timeout_ms, go back and reconsider. (We
// never timeout indefinitely, so we can check the shutdown
// flag every once in a while.)
interrupted = true;
} else if (_num_results < 0) {
// If our poll was interrupted by another thread, rebuild the
// list and poll again.
PRErrorCode errcode = PR_GetError();
if (errcode == PR_PENDING_INTERRUPT_ERROR) {
interrupted = true;
} else {
pprerror("PR_Poll");
}
// If we had an error, just return.
return (SocketInfo *)NULL;
}
} while (!_shutdown && interrupted);
PR_AtomicSet(&_currently_polling_thread, -1);
// Just in case someone interrupted us while we were polling and
// we didn't catch it, clear it now--we don't care any more.
PR_ClearInterrupt();
AtomicAdjust::set(_currently_polling_thread, current_thread_index);
// Repeat the above until we (a) find a socket with actual noise
// on it, or (b) return from PR_Poll() with no sockets available.
} while (!_shutdown && _num_results > 0);
PR_Unlock(_select_mutex);
return (SocketInfo *)NULL;
}
////////////////////////////////////////////////////////////////////
// Function: ConnectionReader::rebuild_poll_list
// Function: ConnectionReader::rebuild_select_list
// Access: Private
// Description: Rebuilds the _poll and _polled_sockets arrays based
// on the sockets that are currently available for
// polling.
// Description: Rebuilds the _fdset and _selecting_sockets arrays
// based on the sockets that are currently available for
// selecting.
////////////////////////////////////////////////////////////////////
void ConnectionReader::
rebuild_poll_list() {
_poll.clear();
_polled_sockets.clear();
rebuild_select_list() {
_fdset.clear();
_selecting_sockets.clear();
PR_Lock(_sockets_mutex);
MutexHolder holder(_sockets_mutex);
Sockets::const_iterator si;
for (si = _sockets.begin(); si != _sockets.end(); ++si) {
SocketInfo *sinfo = (*si);
if (!sinfo->_busy && !sinfo->_error) {
PRPollDesc pd;
pd.fd = sinfo->get_socket();
pd.in_flags = PR_POLL_READ;
pd.out_flags = 0;
_poll.push_back(pd);
_polled_sockets.push_back(sinfo);
_fdset.setForSocket(*sinfo->get_socket());
_selecting_sockets.push_back(sinfo);
}
}
@ -1056,6 +869,4 @@ rebuild_poll_list() {
}
_removed_sockets.swap(still_busy_sockets);
}
PR_Unlock(_sockets_mutex);
}

View File

@ -24,15 +24,15 @@
#include "connection.h"
#include "pointerTo.h"
#include <prio.h>
#include <prthread.h>
#include <prlock.h>
#include "pmutex.h"
#include "pvector.h"
#include "pset.h"
#include "socket_fdset.h"
class NetDatagram;
class ConnectionManager;
class Socket_Address;
class Socket_IP;
////////////////////////////////////////////////////////////////////
// Class : ConnectionReader
@ -72,9 +72,9 @@ PUBLISHED:
ConnectionReader(ConnectionManager *manager, int num_threads);
virtual ~ConnectionReader();
bool add_connection(const PT(Connection) &connection);
bool remove_connection(const PT(Connection) &connection);
bool is_connection_ok(const PT(Connection) &connection);
bool add_connection(Connection *connection);
bool remove_connection(Connection *connection);
bool is_connection_ok(Connection *connection);
void poll();
@ -95,7 +95,7 @@ protected:
public:
SocketInfo(const PT(Connection) &connection);
bool is_udp() const;
PRFileDesc *get_socket() const;
Socket_IP *get_socket() const;
PT(Connection) _connection;
bool _busy;
@ -113,13 +113,12 @@ protected:
virtual void process_raw_incoming_tcp_data(SocketInfo *sinfo);
private:
static void thread_start(void *data);
void thread_run();
void thread_run(int thread_index);
SocketInfo *get_next_available_socket(PRIntervalTime timeout,
PRInt32 current_thread_index);
SocketInfo *get_next_available_socket(bool allow_block,
int current_thread_index);
void rebuild_poll_list();
void rebuild_select_list();
protected:
ConnectionManager *_manager;
@ -129,27 +128,34 @@ private:
int _tcp_header_size;
bool _shutdown;
typedef pvector<PRThread *> Threads;
class ReaderThread : public Thread {
public:
ReaderThread(ConnectionReader *reader, int thread_index);
virtual void thread_main();
ConnectionReader *_reader;
int _thread_index;
};
typedef pvector< PT(ReaderThread) > Threads;
Threads _threads;
PRLock *_startup_mutex;
bool _polling;
// These structures are used to manage polling for noise on
// These structures are used to manage selecting for noise on
// available sockets.
typedef pvector<PRPollDesc> Poll;
Socket_fdset _fdset;
typedef pvector<SocketInfo *> Sockets;
Poll _poll;
Sockets _polled_sockets;
Sockets _selecting_sockets;
int _next_index;
int _num_results;
// Threads go to sleep on this mutex waiting for their chance to
// read a socket.
PRLock *_select_mutex;
Mutex _select_mutex;
// This is atomically updated with the index (in _threads) of the
// thread that is currently waiting on the PR_Poll() call. It
// contains -1 if no thread is so waiting.
PRInt32 _currently_polling_thread;
PN_int32 _currently_polling_thread;
// These structures track the total set of sockets (connections) we
// know about.
@ -157,14 +163,12 @@ private:
// This is the list of recently-removed sockets. We can't actually
// delete them until they're no longer _busy.
Sockets _removed_sockets;
// Threads may set this true to force the polling thread to rebuild
// its Poll() list.
bool _reexamine_sockets;
// Any operations on _sockets are protected by this mutex.
PRLock *_sockets_mutex;
Mutex _sockets_mutex;
friend class ConnectionManager;
friend class ConnectionManager;
friend class ReaderThread;
};
#endif

View File

@ -19,11 +19,33 @@
#include "connectionWriter.h"
#include "connectionManager.h"
#include "datagramTCPHeader.h"
#include "pprerror.h"
#include "config_net.h"
#include "socket_tcp.h"
#include "socket_udp.h"
#include "pnotify.h"
#include <prerror.h>
////////////////////////////////////////////////////////////////////
// Function: ConnectionWriter::WriterThread::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
ConnectionWriter::WriterThread::
WriterThread(ConnectionWriter *writer, int thread_index) :
Thread("WriterThread", "WriterThread"),
_writer(writer),
_thread_index(thread_index)
{
}
////////////////////////////////////////////////////////////////////
// Function: ConnectionWriter::WriterThread::thread_main
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void ConnectionWriter::WriterThread::
thread_main() {
_writer->thread_run(_thread_index);
}
////////////////////////////////////////////////////////////////////
// Function: ConnectionWriter::Constructor
@ -57,18 +79,14 @@ ConnectionWriter(ConnectionManager *manager, int num_threads) :
_tcp_header_size = datagram_tcp16_header_size;
_immediate = (num_threads <= 0);
for (int i = 0; i < num_threads; i++) {
PRThread *thread =
PR_CreateThread(PR_USER_THREAD,
thread_start, (void *)this,
PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD, // Since thread will mostly do I/O.
PR_JOINABLE_THREAD,
0); // Select a suitable stack size.
nassertv(thread != (PRThread *)NULL);
int i;
for (i = 0; i < num_threads; i++) {
PT(WriterThread) thread = new WriterThread(this, i);
_threads.push_back(thread);
}
for (i = 0; i < num_threads; i++) {
_threads[i]->start(TP_normal, true, true);
}
_manager->add_writer(this);
}
@ -91,16 +109,7 @@ ConnectionWriter::
// Now wait for all threads to terminate.
Threads::iterator ti;
for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
// Interrupt the thread just in case it was stuck waiting for I/O.
PRStatus result = PR_Interrupt(*ti);
if (result != PR_SUCCESS) {
pprerror("PR_Interrupt");
}
result = PR_JoinThread(*ti);
if (result != PR_SUCCESS) {
pprerror("PR_JoinThread");
}
(*ti)->join();
}
}
@ -123,7 +132,7 @@ ConnectionWriter::
bool ConnectionWriter::
send(const Datagram &datagram, const PT(Connection) &connection) {
nassertr(connection != (Connection *)NULL, false);
nassertr(PR_GetDescType(connection->get_socket()) == PR_DESC_SOCKET_TCP, false);
nassertr(connection->get_socket()->is_exact_type(Socket_TCP::get_class_type()), false);
NetDatagram copy(datagram);
copy.set_connection(connection);
@ -159,10 +168,9 @@ bool ConnectionWriter::
send(const Datagram &datagram, const PT(Connection) &connection,
const NetAddress &address) {
nassertr(connection != (Connection *)NULL, false);
nassertr(PR_GetDescType(connection->get_socket()) == PR_DESC_SOCKET_UDP, false);
nassertr(connection->get_socket()->is_exact_type(Socket_UDP::get_class_type()), false);
if (PR_GetDescType(connection->get_socket()) == PR_DESC_SOCKET_UDP &&
(int)datagram.get_length() > maximum_udp_datagram) {
if ((int)datagram.get_length() > maximum_udp_datagram) {
net_cat.warning()
<< "Attempt to send UDP datagram of " << datagram.get_length()
<< " bytes, more than the\n"
@ -299,19 +307,6 @@ clear_manager() {
_manager = (ConnectionManager *)NULL;
}
////////////////////////////////////////////////////////////////////
// Function: ConnectionWriter::thread_start
// Access: Private, Static
// Description: The static wrapper around the thread's executing
// function. This must be a static member function
// because it is passed through the C interface to
// PR_CreateThread().
////////////////////////////////////////////////////////////////////
void ConnectionWriter::
thread_start(void *data) {
((ConnectionWriter *)data)->thread_run();
}
////////////////////////////////////////////////////////////////////
// Function: ConnectionWriter::thread_run
// Access: Private
@ -319,7 +314,7 @@ thread_start(void *data) {
// thread.
////////////////////////////////////////////////////////////////////
void ConnectionWriter::
thread_run() {
thread_run(int thread_index) {
nassertv(!_immediate);
NetDatagram datagram;

View File

@ -20,13 +20,10 @@
#define CONNECTIONWRITER_H
#include "pandabase.h"
#include "datagramQueue.h"
#include "connection.h"
#include "pointerTo.h"
#include <prthread.h>
#include "thread.h"
#include "pvector.h"
class ConnectionManager;
@ -38,7 +35,7 @@ class NetAddress;
// various TCP or UDP sockets.
//
// A ConnectionWriter may define an arbitrary number of
// threads (at least one) to write its datagrams to
// threads (0 or more) to write its datagrams to
// sockets. The number of threads is specified at
// construction time and cannot be changed.
////////////////////////////////////////////////////////////////////
@ -70,8 +67,7 @@ protected:
void clear_manager();
private:
static void thread_start(void *data);
void thread_run();
void thread_run(int thread_index);
bool send_datagram(const NetDatagram &datagram);
protected:
@ -82,11 +78,22 @@ private:
int _tcp_header_size;
DatagramQueue _queue;
typedef pvector<PRThread *> Threads;
class WriterThread : public Thread {
public:
WriterThread(ConnectionWriter *writer, int thread_index);
virtual void thread_main();
ConnectionWriter *_writer;
int _thread_index;
};
typedef pvector< PT(WriterThread) > Threads;
Threads _threads;
bool _immediate;
friend class ConnectionManager;
friend class ConnectionManager;
friend class WriterThread;
};
#endif

View File

@ -18,6 +18,7 @@
#include "datagramQueue.h"
#include "config_net.h"
#include "mutexHolder.h"
////////////////////////////////////////////////////////////////////
// Function: DatagramQueue::Constructor
@ -25,10 +26,8 @@
// Description:
////////////////////////////////////////////////////////////////////
DatagramQueue::
DatagramQueue() {
DatagramQueue() : _cv(_cvlock) {
_shutdown = false;
_cvlock = PR_NewLock();
_cv = PR_NewCondVar(_cvlock);
_max_queue_size = get_net_max_write_queue();
}
@ -42,9 +41,6 @@ DatagramQueue::
// It's an error to delete a DatagramQueue without first shutting it
// down (and waiting for any associated threads to terminate).
nassertv(_shutdown);
PR_DestroyCondVar(_cv);
PR_DestroyLock(_cvlock);
}
////////////////////////////////////////////////////////////////////
@ -61,10 +57,10 @@ void DatagramQueue::
shutdown() {
// Notify all of our threads that we're shutting down. This will
// cause any thread blocking on extract() to return false.
PR_Lock(_cvlock);
MutexHolder holder(_cvlock);
_shutdown = true;
PR_NotifyAllCondVar(_cv);
PR_Unlock(_cvlock);
_cv.signal_all();
}
@ -79,17 +75,14 @@ shutdown() {
////////////////////////////////////////////////////////////////////
bool DatagramQueue::
insert(const NetDatagram &data) {
PR_Lock(_cvlock);
MutexHolder holder(_cvlock);
bool enqueue_ok = ((int)_queue.size() < _max_queue_size);
if (enqueue_ok) {
#ifdef __ICL
_queue.push_back(new NetDatagram(data));
#else
_queue.push_back(data);
#endif
}
PR_NotifyCondVar(_cv);
PR_Unlock(_cvlock);
_cv.signal();
return enqueue_ok;
}
@ -118,27 +111,20 @@ extract(NetDatagram &result) {
// connection pointer--we're about to go to sleep for a while.
result.clear();
PR_Lock(_cvlock);
MutexHolder holder(_cvlock);
while (_queue.empty() && !_shutdown) {
PR_WaitCondVar(_cv, PR_INTERVAL_NO_TIMEOUT);
_cv.wait();
}
if (_shutdown) {
PR_Unlock(_cvlock);
return false;
}
nassertr(!_queue.empty(), false);
#ifdef __ICL
NetDatagram *ptr = _queue.front();
result = *ptr;
delete ptr;
#else
result = _queue.front();
#endif
_queue.pop_front();
PR_Unlock(_cvlock);
return true;
}
@ -156,9 +142,8 @@ extract(NetDatagram &result) {
////////////////////////////////////////////////////////////////////
void DatagramQueue::
set_max_queue_size(int max_size) {
PR_Lock(_cvlock);
MutexHolder holder(_cvlock);
_max_queue_size = max_size;
PR_Unlock(_cvlock);
}
////////////////////////////////////////////////////////////////////
@ -179,8 +164,7 @@ get_max_queue_size() const {
////////////////////////////////////////////////////////////////////
int DatagramQueue::
get_current_queue_size() const {
PR_Lock(_cvlock);
MutexHolder holder(_cvlock);
int size = _queue.size();
PR_Unlock(_cvlock);
return size;
}

View File

@ -22,9 +22,8 @@
#include "pandabase.h"
#include "netDatagram.h"
#include <prlock.h>
#include <prcvar.h>
#include "pmutex.h"
#include "conditionVarFull.h"
#include "pdeque.h"
////////////////////////////////////////////////////////////////////
@ -47,17 +46,10 @@ public:
int get_current_queue_size() const;
private:
PRLock *_cvlock;
PRCondVar *_cv;
Mutex _cvlock;
ConditionVarFull _cv;
#ifdef __ICL
// The Intel compiler for some reason dumps core on a queue of
// NetDatagrams.
typedef pdeque<NetDatagram *> QueueType;
#else
typedef pdeque<NetDatagram> QueueType;
#endif
QueueType _queue;
bool _shutdown;
int _max_queue_size;

View File

@ -38,7 +38,7 @@ DatagramTCPHeader(const NetDatagram &datagram, int header_size) {
case datagram_tcp16_header_size:
{
PRUint16 size = str.length();
PN_uint16 size = str.length();
nassertv(size == str.length());
_header.add_uint16(size);
}
@ -46,7 +46,7 @@ DatagramTCPHeader(const NetDatagram &datagram, int header_size) {
case datagram_tcp32_header_size:
{
PRUint32 size = str.length();
PN_uint32 size = str.length();
nassertv(size == str.length());
_header.add_uint32(size);
}

View File

@ -24,11 +24,10 @@
#include "netDatagram.h"
#include "datagramIterator.h"
#include "numeric_types.h"
#include <prtypes.h>
static const int datagram_tcp16_header_size = sizeof(PRUint16);
static const int datagram_tcp32_header_size = sizeof(PRUint32);
static const int datagram_tcp16_header_size = sizeof(PN_uint16);
static const int datagram_tcp32_header_size = sizeof(PN_uint32);
class NetDatagram;

View File

@ -32,9 +32,9 @@
DatagramUDPHeader::
DatagramUDPHeader(const NetDatagram &datagram) {
const string &str = datagram.get_message();
PRUint16 checksum = 0;
PN_uint16 checksum = 0;
for (size_t p = 0; p < str.size(); p++) {
checksum += (PRUint16)(PRUint8)str[p];
checksum += (PN_uint16)(PN_uint8)str[p];
}
// Now pack the header.
@ -64,9 +64,9 @@ bool DatagramUDPHeader::
verify_datagram(const NetDatagram &datagram) const {
const string &str = datagram.get_message();
PRUint16 checksum = 0;
PN_uint16 checksum = 0;
for (size_t p = 0; p < str.size(); p++) {
checksum += (PRUint16)(PRUint8)str[p];
checksum += (PN_uint16)(PN_uint8)str[p];
}
if (checksum == get_datagram_checksum()) {

View File

@ -24,10 +24,9 @@
#include "netDatagram.h"
#include "datagramIterator.h"
#include "numeric_types.h"
#include <prtypes.h>
static const int datagram_udp_header_size = sizeof(PRUint16);
static const int datagram_udp_header_size = sizeof(PN_uint16);
class NetDatagram;

View File

@ -17,12 +17,8 @@
////////////////////////////////////////////////////////////////////
#include "netAddress.h"
#include "pprerror.h"
#include "config_net.h"
#include <prio.h>
#include <prnetdb.h>
////////////////////////////////////////////////////////////////////
// Function: NetAddress::Constructor
@ -31,19 +27,18 @@
////////////////////////////////////////////////////////////////////
NetAddress::
NetAddress() {
PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &_addr);
}
////////////////////////////////////////////////////////////////////
// Function: NetAddress::Constructor
// Access: Public
// Description: Constructs an address from a given PRNetAddr.
// Description: Constructs an address from a given Socket_Address.
// Normally, this constructor should not be used by user
// code; instead, create a default NetAddress and use
// one of the set_*() functions to set up an address.
////////////////////////////////////////////////////////////////////
NetAddress::
NetAddress(const PRNetAddr &addr) : _addr(addr) {
NetAddress(const Socket_Address &addr) : _addr(addr) {
}
@ -57,9 +52,7 @@ NetAddress(const PRNetAddr &addr) : _addr(addr) {
////////////////////////////////////////////////////////////////////
bool NetAddress::
set_any(int port) {
PR_InitializeNetAddr(PR_IpAddrAny, port, &_addr);
return true;
return _addr.set_any_IP(port);
}
////////////////////////////////////////////////////////////////////
@ -70,9 +63,7 @@ set_any(int port) {
////////////////////////////////////////////////////////////////////
bool NetAddress::
set_localhost(int port) {
PR_InitializeNetAddr(PR_IpAddrLoopback, port, &_addr);
return true;
return _addr.set_host("127.0.0.1", port);
}
////////////////////////////////////////////////////////////////////
@ -84,90 +75,7 @@ set_localhost(int port) {
////////////////////////////////////////////////////////////////////
bool NetAddress::
set_host(const string &hostname, int port) {
// If the hostname appears to be a dot-separated IPv4 address, then
// parse it directly and store it. Some OS system libraries
// (notably Win95) can't parse this themselves.
union {
PRUint32 l;
unsigned char n[4];
} ipaddr;
int ni = 0;
bool is_ip = true;
size_t p = 0;
size_t q = 0;
unsigned int num = 0;
while (p < hostname.length() && ni < 4 && is_ip) {
if (hostname[p] == '.' && p > q) {
// Now we have a number between q and p.
ipaddr.n[ni] = (unsigned char)num;
p++;
q = p;
num = 0;
ni++;
if (num >= 256 || ni >= 4) {
is_ip = false;
}
} else if (isdigit(hostname[p])) {
num = 10 * num + (unsigned int)(hostname[p] - '0');
p++;
if (num >= 256) {
is_ip = false;
}
} else {
is_ip = false;
}
}
if (p == hostname.length() && ni < 4 && is_ip && p > q) {
ipaddr.n[ni] = (unsigned char)num;
ni++;
if (num >= 256) {
is_ip = false;
}
}
if (p == hostname.length() && ni == 4 && is_ip) {
net_cat.debug()
<< "Parsed IP " << (int)ipaddr.n[0] << "." << (int)ipaddr.n[1]
<< "." << (int)ipaddr.n[2] << "." << (int)ipaddr.n[3] << "\n";
memset(&_addr, 0, sizeof(PRNetAddr));
_addr.inet.family = PR_AF_INET;
_addr.inet.port = PR_htons(port);
_addr.inet.ip = ipaddr.l;
} else {
// If it's not a numeric IPv4 address, pass the whole thing on to
// GetHostByName and let NSPR deal with it.
char buf[PR_NETDB_BUF_SIZE];
PRHostEnt host;
PRStatus result =
PR_GetHostByName(hostname.c_str(), buf, PR_NETDB_BUF_SIZE, &host);
if (result != PR_SUCCESS) {
pprerror("PR_GetHostByName");
net_cat.error()
<< "Unable to look up hostname " << hostname << ".\n";
return false;
}
PRIntn next = PR_EnumerateHostEnt(0, &host, port, &_addr);
if (next == -1) {
pprerror("PR_EnumerateHostEnt");
return false;
} else if (next == 0) {
net_cat.error()
<< "No addresses available for " << hostname << ".\n";
return false;
}
}
return true;
return _addr.set_host(hostname, port);
}
////////////////////////////////////////////////////////////////////
@ -177,7 +85,7 @@ set_host(const string &hostname, int port) {
////////////////////////////////////////////////////////////////////
void NetAddress::
clear() {
PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &_addr);
_addr.clear();
}
////////////////////////////////////////////////////////////////////
@ -187,7 +95,7 @@ clear() {
////////////////////////////////////////////////////////////////////
int NetAddress::
get_port() const {
return PR_ntohs(_addr.inet.port);
return _addr.get_port();
}
////////////////////////////////////////////////////////////////////
@ -198,7 +106,7 @@ get_port() const {
////////////////////////////////////////////////////////////////////
void NetAddress::
set_port(int port) {
PR_InitializeNetAddr(PR_IpAddrNull, port, &_addr);
_addr.set_port(port);
}
////////////////////////////////////////////////////////////////////
@ -209,17 +117,7 @@ set_port(int port) {
////////////////////////////////////////////////////////////////////
string NetAddress::
get_ip_string() const {
static const int buf_len = 1024;
char buf[buf_len];
PRStatus result =
PR_NetAddrToString(&_addr, buf, buf_len);
if (result != PR_SUCCESS) {
pprerror("PR_NetAddrToString");
return "error";
}
return string(buf);
return _addr.get_ip();
}
////////////////////////////////////////////////////////////////////
@ -230,7 +128,7 @@ get_ip_string() const {
////////////////////////////////////////////////////////////////////
PN_uint32 NetAddress::
get_ip() const {
return PR_ntohl(_addr.inet.ip);
return _addr.GetIPAddressRaw();
}
////////////////////////////////////////////////////////////////////
@ -244,7 +142,8 @@ get_ip() const {
PN_uint8 NetAddress::
get_ip_component(int n) const {
nassertr(n >= 0 && n < 4, 0);
const PN_uint8 *ip = (const PN_uint8 *)&_addr.inet.ip;
PN_uint32 ip_long = _addr.GetIPAddressRaw();
const PN_uint8 *ip = (const PN_uint8 *)&ip_long;
return ip[n];
}
@ -252,11 +151,11 @@ get_ip_component(int n) const {
////////////////////////////////////////////////////////////////////
// Function: NetAddress::get_addr
// Access: Public
// Description: Returns the PRNetAddr for this address.
// Description: Returns the Socket_Address for this address.
////////////////////////////////////////////////////////////////////
PRNetAddr *NetAddress::
const Socket_Address &NetAddress::
get_addr() const {
return (PRNetAddr *)&_addr;
return _addr;
}
////////////////////////////////////////////////////////////////////

View File

@ -21,8 +21,7 @@
#include "pandabase.h"
#include "numeric_types.h"
#include <prio.h>
#include "socket_address.h"
////////////////////////////////////////////////////////////////////
// Class : NetAddress
@ -32,7 +31,7 @@
class EXPCL_PANDA NetAddress {
PUBLISHED:
NetAddress();
NetAddress(const PRNetAddr &addr);
NetAddress(const Socket_Address &addr);
bool set_any(int port);
bool set_localhost(int port);
@ -46,12 +45,12 @@ PUBLISHED:
PN_uint32 get_ip() const;
PN_uint8 get_ip_component(int n) const;
PRNetAddr *get_addr() const;
const Socket_Address &get_addr() const;
void output(ostream &out) const;
private:
PRNetAddr _addr;
Socket_Address _addr;
};
INLINE ostream &operator << (ostream &out, const NetAddress &addr) {

View File

@ -1,6 +1,5 @@
#include "config_net.cxx"
#include "pprerror.cxx"
#include "connection.cxx"
#include "connectionListener.cxx"
#include "connectionManager.cxx"

View File

@ -1,238 +0,0 @@
// Filename: pprerror.cxx
// Created by: drose (08Feb00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "pandabase.h"
#include "pprerror.h"
#include "config_net.h"
#include <prerror.h>
#include <prprf.h>
#include <prmem.h>
#include <stdarg.h>
#include <stdio.h>
static const char *get_error_message(PRErrorCode code);
////////////////////////////////////////////////////////////////////
// Function: pprerror
// Description: A handy function like perror(). It outputs the
// printf-style format string and its arguments,
// followed by a colon and the NSPR-given description of
// its current error state.
////////////////////////////////////////////////////////////////////
void
pprerror(const char *format, ...) {
va_list ap;
va_start(ap, format);
char *str = PR_vsprintf_append(NULL, format, ap);
if (str == (char *)NULL) {
net_cat.error()
<< string("Invalid format string: ") + format + "\n";
return;
}
PRErrorCode code = PR_GetError();
const char *error_message = get_error_message(code);
if (error_message == (const char *)NULL) {
str = PR_sprintf_append(str, ": (%d)\n", code);
} else {
str = PR_sprintf_append(str, ": %s (%d)\n", error_message, code);
}
net_cat.error() << str;
PR_Free(str);
if (get_net_error_abort()) {
abort();
}
va_end(ap);
}
////////////////////////////////////////////////////////////////////
// Function: get_error_message
// Description: A local function to this module, it returns a
// sensibly formatted string to describe the given NSPR
// error code. The strings in this function were
// extracted from the NSPR documentation web site.
////////////////////////////////////////////////////////////////////
static const char *
get_error_message(PRErrorCode code) {
switch (code) {
case PR_OUT_OF_MEMORY_ERROR:
return "PR_OUT_OF_MEMORY_ERROR--Insufficient memory to perform request.";
case PR_BAD_DESCRIPTOR_ERROR:
return "PR_BAD_DESCRIPTOR_ERROR--The file descriptor used as an argument in the preceding function is invalid.";
case PR_WOULD_BLOCK_ERROR:
return "PR_WOULD_BLOCK_ERROR--The operation would have blocked, which conflicts with the semantics that have been established.";
case PR_ACCESS_FAULT_ERROR:
return "PR_ACCESS_FAULT_ERROR--One of the arguments of the preceding function specified an invalid memory address.";
case PR_INVALID_METHOD_ERROR:
return "PR_INVALID_METHOD_ERROR--The preceding function is invalid for the type of file descriptor used.";
case PR_ILLEGAL_ACCESS_ERROR:
return "PR_ILLEGAL_ACCESS_ERROR--One of the arguments of the preceding function specified an invalid memory address.";
case PR_UNKNOWN_ERROR:
return "PR_UNKNOWN_ERROR--Some unknown error has occurred.";
case PR_PENDING_INTERRUPT_ERROR:
return "PR_PENDING_INTERRUPT_ERROR--The operation terminated because another thread has interrupted it with PR_Interrupt.";
case PR_NOT_IMPLEMENTED_ERROR:
return "PR_NOT_IMPLEMENTED_ERROR--The preceding function has not been implemented.";
case PR_IO_ERROR:
return "PR_IO_ERROR--The preceding I/O function encountered some sort of an error, perhaps an invalid device.";
case PR_IO_TIMEOUT_ERROR:
return "PR_IO_TIMEOUT_ERROR--The I/O operation has not completed in the time specified for the preceding function.";
case PR_IO_PENDING_ERROR:
return "PR_IO_PENDING_ERROR--An I/O operation has been attempted on a file descriptor that is currently busy with another operation.";
case PR_DIRECTORY_OPEN_ERROR:
return "PR_DIRECTORY_OPEN_ERROR--The directory could not be opened.";
case PR_INVALID_ARGUMENT_ERROR:
return "PR_INVALID_ARGUMENT_ERROR--One or more of the arguments to the function is invalid.";
case PR_ADDRESS_NOT_AVAILABLE_ERROR:
return "PR_ADDRESS_NOT_AVAILABLE_ERROR--The network address (PRNetAddr) is not available (probably in use).";
case PR_ADDRESS_NOT_SUPPORTED_ERROR:
return "PR_ADDRESS_NOT_SUPPORTED_ERROR--The type of network address specified is not supported.";
case PR_IS_CONNECTED_ERROR:
return "PR_IS_CONNECTED_ERROR--An attempt to connect on an already connected network file descriptor.";
case PR_BAD_ADDRESS_ERROR:
return "PR_BAD_ADDRESS_ERROR--The network address specified is invalid (as reported by the network).";
case PR_ADDRESS_IN_USE_ERROR:
return "PR_ADDRESS_IN_USE_ERROR--Network address specified (PRNetAddr) is in use.";
case PR_CONNECT_REFUSED_ERROR:
return "PR_CONNECT_REFUSED_ERROR--The peer has refused to allow the connection to be established.";
case PR_NETWORK_UNREACHABLE_ERROR:
return "PR_NETWORK_UNREACHABLE_ERROR--The network address specifies a host that is unreachable (perhaps temporary).";
case PR_CONNECT_TIMEOUT_ERROR:
return "PR_CONNECT_TIMEOUT_ERROR--The connection attempt did not complete in a reasonable period of time.";
case PR_NOT_CONNECTED_ERROR:
return "PR_NOT_CONNECTED_ERROR--The preceding function attempted to use connected semantics on a network file descriptor that was not connected.";
case PR_LOAD_LIBRARY_ERROR:
return "PR_LOAD_LIBRARY_ERROR--Failure to load a dynamic library.";
case PR_UNLOAD_LIBRARY_ERROR:
return "PR_UNLOAD_LIBRARY_ERROR--Failure to unload a dynamic library.";
case PR_FIND_SYMBOL_ERROR:
return "PR_FIND_SYMBOL_ERROR--Symbol could not be found in the specified library.";
case PR_INSUFFICIENT_RESOURCES_ERROR:
return "PR_INSUFFICIENT_RESOURCES_ERROR--There are insufficient system resources to process the request.";
case PR_DIRECTORY_LOOKUP_ERROR:
return "PR_DIRECTORY_LOOKUP_ERROR--A directory lookup on a network address has failed.";
case PR_TPD_RANGE_ERROR:
return "PR_TPD_RANGE_ERROR--Attempt to access a thread-private data index that is out of range of any index that has been allocated to the process.";
case PR_PROC_DESC_TABLE_FULL_ERROR:
return "PR_PROC_DESC_TABLE_FULL_ERROR--The process' table for holding open file descriptors is full.";
case PR_SYS_DESC_TABLE_FULL_ERROR:
return "PR_SYS_DESC_TABLE_FULL_ERROR--The system's table for holding open file descriptors has been exceeded.";
case PR_NOT_SOCKET_ERROR:
return "PR_NOT_SOCKET_ERROR--An attempt to use a non-network file descriptor on a network-only operation.";
case PR_NOT_TCP_SOCKET_ERROR:
return "PR_NOT_TCP_SOCKET_ERROR--Attempt to perform a TCP specific function on a non-TCP file descriptor.";
case PR_SOCKET_ADDRESS_IS_BOUND_ERROR:
return "PR_SOCKET_ADDRESS_IS_BOUND_ERROR--Attempt to bind an address to a TCP file descriptor that is already bound.";
case PR_NO_ACCESS_RIGHTS_ERROR:
return "PR_NO_ACCESS_RIGHTS_ERROR--Calling thread does not have privilege to perform the operation requested.";
case PR_OPERATION_NOT_SUPPORTED_ERROR:
return "PR_OPERATION_NOT_SUPPORTED_ERROR--The requested operation is not supported by the platform.";
case PR_PROTOCOL_NOT_SUPPORTED_ERROR:
return "PR_PROTOCOL_NOT_SUPPORTED_ERROR--The host operating system does not support the protocol requested.";
case PR_REMOTE_FILE_ERROR:
return "PR_REMOTE_FILE_ERROR--Access to the remote file has been severed.";
case PR_BUFFER_OVERFLOW_ERROR:
return "PR_BUFFER_OVERFLOW_ERROR--The value retrieved is too large to be stored in the buffer provided.";
case PR_CONNECT_RESET_ERROR:
return "PR_CONNECT_RESET_ERROR--The (TCP) connection has been reset by the peer.";
case PR_RANGE_ERROR:
return "PR_RANGE_ERROR--Unused.";
case PR_DEADLOCK_ERROR:
return "PR_DEADLOCK_ERROR--Performing the requested operation would have caused a deadlock. The deadlock was avoided.";
case PR_FILE_IS_LOCKED_ERROR:
return "PR_FILE_IS_LOCKED_ERROR--An attempt to acquire a lock on a file has failed because the file is already locked.";
case PR_FILE_TOO_BIG_ERROR:
return "PR_FILE_TOO_BIG_ERROR--Completing the write or seek operation would have resulted in a file larger than the system could handle.";
case PR_NO_DEVICE_SPACE_ERROR:
return "PR_NO_DEVICE_SPACE_ERROR--The device for storing the file is full.";
case PR_PIPE_ERROR:
return "PR_PIPE_ERROR--Unused.";
case PR_NO_SEEK_DEVICE_ERROR:
return "PR_NO_SEEK_DEVICE_ERROR--Unused.";
case PR_IS_DIRECTORY_ERROR:
return "PR_IS_DIRECTORY_ERROR--Attempt to perform a normal file operation on a directory.";
case PR_LOOP_ERROR:
return "PR_LOOP_ERROR--Symbolic link loop.";
case PR_NAME_TOO_LONG_ERROR:
return "PR_NAME_TOO_LONG_ERROR--Filename is longer than allowed by the host operating system.";
case PR_FILE_NOT_FOUND_ERROR:
return "PR_FILE_NOT_FOUND_ERROR--The requested file was not found.";
case PR_NOT_DIRECTORY_ERROR:
return "PR_NOT_DIRECTORY_ERROR--Attempt to perform directory specific operations on a normal file.";
case PR_READ_ONLY_FILESYSTEM_ERROR:
return "PR_READ_ONLY_FILESYSTEM_ERROR--Attempt to write to a read-only file system.";
case PR_DIRECTORY_NOT_EMPTY_ERROR:
return "PR_DIRECTORY_NOT_EMPTY_ERROR--Attempt to delete a directory that is not empty.";
case PR_FILESYSTEM_MOUNTED_ERROR:
return "PR_FILESYSTEM_MOUNTED_ERROR--Attempt to delete or rename a file object while the file system is busy.";
case PR_NOT_SAME_DEVICE_ERROR:
return "PR_NOT_SAME_DEVICE_ERROR--Request to rename a file to a file system on another device.";
case PR_DIRECTORY_CORRUPTED_ERROR:
return "PR_DIRECTORY_CORRUPTED_ERROR--The directory object in the file system is corrupted.";
case PR_FILE_EXISTS_ERROR:
return "PR_FILE_EXISTS_ERROR--Attempt to create or rename a file when the new name is already being used.";
case PR_MAX_DIRECTORY_ENTRIES_ERROR:
return "PR_MAX_DIRECTORY_ENTRIES_ERROR--Attempt to add new filename to directory would exceed the limit allowed.";
case PR_INVALID_DEVICE_STATE_ERROR:
return "PR_INVALID_DEVICE_STATE_ERROR--The device was in an invalid state to complete the desired operation.";
case PR_DEVICE_IS_LOCKED_ERROR:
return "PR_DEVICE_IS_LOCKED_ERROR--The device needed to perform the desired request is locked.";
case PR_NO_MORE_FILES_ERROR:
return "PR_NO_MORE_FILES_ERROR--There are no more entries in the directory.";
case PR_END_OF_FILE_ERROR:
return "PR_END_OF_FILE_ERROR--Unexpectedly encountered end of file (Mac OS only).";
case PR_FILE_SEEK_ERROR:
return "PR_FILE_SEEK_ERROR--An unexpected seek error (Mac OS only).";
case PR_FILE_IS_BUSY_ERROR:
return "PR_FILE_IS_BUSY_ERROR--The file is busy and the operation cannot be performed (Mac OS only).";
case PR_IN_PROGRESS_ERROR:
return "PR_IN_PROGRESS_ERROR--The operation is still in progress (probably a nonblocking connect).";
case PR_ALREADY_INITIATED_ERROR:
return "PR_ALREADY_INITIATED_ERROR--The (retried) operation has already been initiated (probably a nonblocking connect).";
case PR_GROUP_EMPTY_ERROR:
return "PR_GROUP_EMPTY_ERROR--The wait group is empty.";
case PR_INVALID_STATE_ERROR:
return "PR_INVALID_STATE_ERROR--The attempted operation is on an object that was in an improper state to perform the request.";
// These were added with NSPR 4.0.
#ifdef PR_NETWORK_DOWN_ERROR
case PR_NETWORK_DOWN_ERROR:
return "PR_NETWORK_DOWN_ERROR--The network is down.";
case PR_SOCKET_SHUTDOWN_ERROR:
return "PR_SOCKET_SHUTDOWN_ERROR--The socket has been shut down.";
case PR_CONNECT_ABORTED_ERROR:
return "PR_CONNECT_ABORTED_ERROR--The connection has been aborted.";
case PR_HOST_UNREACHABLE_ERROR:
return "PR_HOST_UNREACHABLE_ERROR--The host is unreachable.";
#endif
case PR_MAX_ERROR:
return "PR_MAX_ERROR--Placeholder for the end of the list.";
}
return (const char *)NULL;
}

View File

@ -25,8 +25,6 @@
#include "connection.h"
#include "netAddress.h"
#include "queuedReturn.h"
#include <prlock.h>
#include "pdeque.h"

View File

@ -98,8 +98,8 @@ get_reset_connection(PT(Connection) &connection) {
// been reset.
////////////////////////////////////////////////////////////////////
void QueuedConnectionManager::
connection_reset(const PT(Connection) &connection, PRErrorCode errcode) {
ConnectionManager::connection_reset(connection, errcode);
connection_reset(const PT(Connection) &connection, bool okflag) {
ConnectionManager::connection_reset(connection, okflag);
// Largely, we don't care if this particular queue fills up. If it
// does, it probably just means the user isn't bothering to track

View File

@ -25,8 +25,6 @@
#include "queuedReturn.h"
#include "pdeque.h"
#include <prlock.h>
EXPORT_TEMPLATE_CLASS(EXPCL_PANDA, EXPTP_PANDA, QueuedReturn< PT(Connection) >);
////////////////////////////////////////////////////////////////////
@ -53,7 +51,7 @@ PUBLISHED:
protected:
virtual void connection_reset(const PT(Connection) &connection,
PRErrorCode errcode);
bool okflag);
};
#endif

View File

@ -19,6 +19,7 @@
#include "queuedConnectionReader.h"
#include "config_net.h"
#include "trueClock.h"
#include "mutexHolder.h"
////////////////////////////////////////////////////////////////////
// Function: QueuedConnectionReader::Constructor
@ -30,7 +31,6 @@ QueuedConnectionReader(ConnectionManager *manager, int num_threads) :
ConnectionReader(manager, num_threads)
{
#ifdef SIMULATE_NETWORK_DELAY
_dd_mutex = PR_NewLock();
_delay_active = false;
_min_delay = 0.0;
_delay_variance = 0.0;
@ -47,10 +47,6 @@ QueuedConnectionReader::
// We call shutdown() here to guarantee that all threads are gone
// before the QueuedReturn destructs.
shutdown();
#ifdef SIMULATE_NETWORK_DELAY
PR_DestroyLock(_dd_mutex);
#endif // SIMULATE_NETWORK_DELAY
}
////////////////////////////////////////////////////////////////////
@ -149,11 +145,10 @@ receive_datagram(const NetDatagram &datagram) {
////////////////////////////////////////////////////////////////////
void QueuedConnectionReader::
start_delay(double min_delay, double max_delay) {
PR_Lock(_dd_mutex);
MutexHolder holder(_dd_mutex);
_min_delay = min_delay;
_delay_variance = max(max_delay - min_delay, 0.0);
_delay_active = true;
PR_Unlock(_dd_mutex);
}
////////////////////////////////////////////////////////////////////
@ -165,7 +160,7 @@ start_delay(double min_delay, double max_delay) {
////////////////////////////////////////////////////////////////////
void QueuedConnectionReader::
stop_delay() {
PR_Lock(_dd_mutex);
MutexHolder holder(_dd_mutex);
_delay_active = false;
// Copy the entire contents of the delay queue to the normal queue.
@ -177,8 +172,6 @@ stop_delay() {
}
_delayed.pop_front();
}
PR_Unlock(_dd_mutex);
}
////////////////////////////////////////////////////////////////////
@ -191,7 +184,7 @@ stop_delay() {
void QueuedConnectionReader::
get_delayed() {
if (_delay_active) {
PR_Lock(_dd_mutex);
MutexHolder holder(_dd_mutex);
double now = TrueClock::get_global_ptr()->get_short_time();
while (!_delayed.empty()) {
const DelayedDatagram &dd = _delayed.front();
@ -205,7 +198,6 @@ get_delayed() {
}
_delayed.pop_front();
}
PR_Unlock(_dd_mutex);
}
}
@ -223,7 +215,7 @@ delay_datagram(const NetDatagram &datagram) {
<< "QueuedConnectionReader queue full!\n";
}
} else {
PR_Lock(_dd_mutex);
MutexHolder holder(_dd_mutex);
// Check the delay_active flag again, now that we have grabbed the
// mutex.
if (!_delay_active) {
@ -244,7 +236,6 @@ delay_datagram(const NetDatagram &datagram) {
dd._reveal_time = reveal_time;
dd._datagram = datagram;
}
PR_Unlock(_dd_mutex);
}
}

View File

@ -24,8 +24,7 @@
#include "connectionReader.h"
#include "netDatagram.h"
#include "queuedReturn.h"
#include <prlock.h>
#include "pmutex.h"
#include "pdeque.h"
EXPORT_TEMPLATE_CLASS(EXPCL_PANDA, EXPTP_PANDA, QueuedReturn<NetDatagram>);
@ -67,7 +66,7 @@ private:
NetDatagram _datagram;
};
PRLock *_dd_mutex;
Mutex _dd_mutex;
typedef pdeque<DelayedDatagram> Delayed;
Delayed _delayed;
bool _delay_active;

View File

@ -16,9 +16,6 @@
//
////////////////////////////////////////////////////////////////////
#include "config_net.h"
#include <algorithm>
////////////////////////////////////////////////////////////////////
// Function: QueuedReturn::set_max_queue_size
@ -35,9 +32,8 @@
template<class Thing>
void QueuedReturn<Thing>::
set_max_queue_size(int max_size) {
PR_Lock(_mutex);
MutexHolder holder(_mutex);
_max_queue_size = max_size;
PR_Unlock(_mutex);
}
////////////////////////////////////////////////////////////////////
@ -60,9 +56,8 @@ get_max_queue_size() const {
template<class Thing>
int QueuedReturn<Thing>::
get_current_queue_size() const {
PR_Lock(_mutex);
MutexHolder holder(_mutex);
int size = _things.size();
PR_Unlock(_mutex);
return size;
}
@ -100,7 +95,6 @@ reset_overflow_flag() {
template<class Thing>
QueuedReturn<Thing>::
QueuedReturn() {
_mutex = PR_NewLock();
_available = false;
_max_queue_size = get_net_max_response_queue();
_overflow_flag = false;
@ -114,7 +108,6 @@ QueuedReturn() {
template<class Thing>
QueuedReturn<Thing>::
~QueuedReturn() {
PR_DestroyLock(_mutex);
}
////////////////////////////////////////////////////////////////////
@ -145,18 +138,16 @@ thing_available() const {
template<class Thing>
bool QueuedReturn<Thing>::
get_thing(Thing &result) {
PR_Lock(_mutex);
MutexHolder holder(_mutex);
if (_things.empty()) {
// Huh. Nothing after all.
_available = false;
PR_Unlock(_mutex);
return false;
}
result = _things.front();
_things.pop_front();
_available = !_things.empty();
PR_Unlock(_mutex);
return true;
}
@ -170,7 +161,7 @@ get_thing(Thing &result) {
template<class Thing>
bool QueuedReturn<Thing>::
enqueue_thing(const Thing &thing) {
PR_Lock(_mutex);
MutexHolder holder(_mutex);
bool enqueue_ok = ((int)_things.size() < _max_queue_size);
if (enqueue_ok) {
_things.push_back(thing);
@ -178,7 +169,6 @@ enqueue_thing(const Thing &thing) {
_overflow_flag = true;
}
_available = true;
PR_Unlock(_mutex);
return enqueue_ok;
}
@ -195,7 +185,7 @@ enqueue_thing(const Thing &thing) {
template<class Thing>
bool QueuedReturn<Thing>::
enqueue_unique_thing(const Thing &thing) {
PR_Lock(_mutex);
MutexHolder holder(_mutex);
bool enqueue_ok = ((int)_things.size() < _max_queue_size);
if (enqueue_ok) {
if (find(_things.begin(), _things.end(), thing) == _things.end()) {
@ -210,7 +200,6 @@ enqueue_unique_thing(const Thing &thing) {
_overflow_flag = true;
}
_available = true;
PR_Unlock(_mutex);
return enqueue_ok;
}

View File

@ -24,9 +24,12 @@
#include "connectionListener.h"
#include "connection.h"
#include "netAddress.h"
#include <prlock.h>
#include "pmutex.h"
#include "pdeque.h"
#include "config_net.h"
#include "mutexHolder.h"
#include <algorithm>
////////////////////////////////////////////////////////////////////
// Class : QueuedReturn
@ -56,7 +59,7 @@ protected:
bool enqueue_unique_thing(const Thing &thing);
private:
PRLock *_mutex;
Mutex _mutex;
pdeque<Thing> _things;
bool _available;
int _max_queue_size;

View File

@ -18,6 +18,7 @@
#include "recentConnectionReader.h"
#include "config_net.h"
#include "mutexHolder.h"
////////////////////////////////////////////////////////////////////
// Function: RecentConnectionReader::Constructor
@ -33,7 +34,6 @@ RecentConnectionReader(ConnectionManager *manager) :
// this should be impossible, because we can't receive datagrams
// before we call add_connection().
_available = false;
_mutex = PR_NewLock();
}
////////////////////////////////////////////////////////////////////
@ -46,8 +46,6 @@ RecentConnectionReader::
// We call shutdown() here to guarantee that all threads are gone
// before the RecentConnectionReader destructs.
shutdown();
PR_DestroyLock(_mutex);
}
////////////////////////////////////////////////////////////////////
@ -76,16 +74,14 @@ data_available() {
////////////////////////////////////////////////////////////////////
bool RecentConnectionReader::
get_data(NetDatagram &result) {
PR_Lock(_mutex);
MutexHolder holder(_mutex);
if (!_available) {
// Huh. Nothing after all.
PR_Unlock(_mutex);
return false;
}
result = _datagram;
_available = false;
PR_Unlock(_mutex);
return true;
}
@ -125,8 +121,7 @@ receive_datagram(const NetDatagram &datagram) {
<< " bytes\n";
}
PR_Lock(_mutex);
MutexHolder holder(_mutex);
_datagram = datagram;
_available = true;
PR_Unlock(_mutex);
}

View File

@ -23,8 +23,7 @@
#include "connectionReader.h"
#include "netDatagram.h"
#include <prlock.h>
#include "pmutex.h"
////////////////////////////////////////////////////////////////////
// Class : RecentConnectionReader
@ -53,7 +52,7 @@ protected:
private:
bool _available;
Datagram _datagram;
PRLock *_mutex;
Mutex _mutex;
};
#endif

View File

@ -25,7 +25,7 @@
#include "netAddress.h"
#include "connection.h"
#include "netDatagram.h"
#include "thread.h"
#include "pset.h"
int
@ -99,7 +99,7 @@ main(int argc, char *argv[]) {
}
// Yield the timeslice before we poll again.
PR_Sleep(PR_MillisecondsToInterval(100));
Thread::sleep(0.1);
}
return (0);

View File

@ -22,10 +22,9 @@
#include "netAddress.h"
#include "connection.h"
#include "netDatagram.h"
#include "clockObject.h"
#include "datagram_ui.h"
#include <prinrval.h>
#include "thread.h"
int
main(int argc, char *argv[]) {
@ -69,12 +68,14 @@ main(int argc, char *argv[]) {
int num_sent = 0;
int num_received = 0;
PRIntervalTime last_reported_time = PR_IntervalNow();
PRIntervalTime report_interval = PR_SecondsToInterval(5);
ClockObject *global_clock = ClockObject::get_global_clock();
double last_reported_time = global_clock->get_real_time();
static const double report_interval = 5.0;
while (!lost_connection) {
// Send the datagram.
if (writer.send(datagram, c, host)) {
if (writer.send(datagram, c)) {
num_sent++;
}
@ -99,15 +100,15 @@ main(int argc, char *argv[]) {
}
}
PRIntervalTime now = PR_IntervalNow();
if ((PRIntervalTime)(now - last_reported_time) > report_interval) {
double now = global_clock->get_real_time();
if ((now - last_reported_time) > report_interval) {
nout << "Sent " << num_sent << ", received "
<< num_received << " datagrams.\n";
last_reported_time = now;
}
// Yield the timeslice before we poll again.
// PR_Sleep(PR_MillisecondsToInterval(1));
Thread::sleep(0.001);
}
return (0);

View File

@ -27,8 +27,8 @@
#include "netDatagram.h"
#include "datagram_ui.h"
#include <prinrval.h>
#include "clockObject.h"
#include "thread.h"
#include "pset.h"
#include <sys/time.h>
@ -65,8 +65,10 @@ main(int argc, char *argv[]) {
int num_sent = 0;
int num_received = 0;
PRIntervalTime last_reported_time = PR_IntervalNow();
PRIntervalTime report_interval = PR_SecondsToInterval(5);
ClockObject *global_clock = ClockObject::get_global_clock();
double last_reported_time = global_clock->get_real_time();
static const double report_interval = 5.0;
bool shutdown = false;
while (!shutdown) {
@ -107,15 +109,15 @@ main(int argc, char *argv[]) {
}
}
PRIntervalTime now = PR_IntervalNow();
if ((PRIntervalTime)(now - last_reported_time) > report_interval) {
double now = global_clock->get_real_time();
if ((now - last_reported_time) > report_interval) {
nout << "Sent " << num_sent << ", received "
<< num_received << " datagrams.\n";
last_reported_time = now;
}
// Yield the timeslice before we poll again.
// PR_Sleep(PR_MillisecondsToInterval(1));
Thread::sleep(0.001);
}
return (0);

View File

@ -25,7 +25,7 @@
#include "netAddress.h"
#include "connection.h"
#include "netDatagram.h"
#include "thread.h"
#include "datagram_ui.h"
#include "pset.h"
@ -119,7 +119,7 @@ main(int argc, char *argv[]) {
}
// Yield the timeslice before we poll again.
PR_Sleep(PR_MillisecondsToInterval(100));
Thread::sleep(0.1);
}
return (0);

View File

@ -6,6 +6,7 @@
#begin lib_target
#define TARGET pipeline
#define USE_PACKAGES threads
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx

View File

@ -458,9 +458,14 @@ handle_server_control_message(const PStatServerControlMessage &message) {
// has been lost.
////////////////////////////////////////////////////////////////////
void PStatClientImpl::
connection_reset(const PT(Connection) &connection, PRErrorCode) {
connection_reset(const PT(Connection) &connection, bool) {
if (connection == _tcp_connection) {
_client->client_disconnect();
} else if (connection == _udp_connection) {
pstats_cat.warning()
<< "Trouble sending UDP; switching to TCP only.\n";
_tcp_count_factor = 0.0f;
_udp_count_factor = 1.0f;
} else {
pstats_cat.warning()
<< "Ignoring spurious connection_reset() message\n";

View File

@ -94,7 +94,7 @@ private:
void handle_server_control_message(const PStatServerControlMessage &message);
virtual void connection_reset(const PT(Connection) &connection,
PRErrorCode errcode);
bool okflag);
PStatClient *_client;

View File

@ -18,7 +18,7 @@
#include "pStatServer.h"
#include "pStatReader.h"
#include "thread.h"
#include "config_pstats.h"
////////////////////////////////////////////////////////////////////
@ -146,10 +146,7 @@ void PStatServer::
main_loop(bool *interrupt_flag) {
while (interrupt_flag == (bool *)NULL || !*interrupt_flag) {
poll();
// Not great. This will totally blow in a threaded environment.
// We need a portable way to sleep or block.
PRIntervalTime sleep_timeout = PR_MillisecondsToInterval(100);
PR_Sleep(sleep_timeout);
Thread::sleep(0.1);
}
}
@ -336,7 +333,7 @@ is_thread_safe() {
// parties and clean up gracefully.
////////////////////////////////////////////////////////////////////
void PStatServer::
connection_reset(const PT(Connection) &connection, PRErrorCode errcode) {
connection_reset(const PT(Connection) &connection, bool okflag) {
// Was this a client connection? Tell the reader about it if it
// was.
close_connection(connection);

View File

@ -70,7 +70,7 @@ public:
protected:
virtual void connection_reset(const PT(Connection) &connection,
PRErrorCode errcode);
bool okflag);
private:
void user_guide_bars_changed();