From 81ecc233996dcddfbef707bd9a5099f5d9e5eb13 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Tue, 1 Nov 2005 16:42:51 +0000 Subject: Added suppor /and fix things for SunOS port git-svn-id: http://svn.pjsip.org/repos/pjproject/main@2 74dad513-b988-da41-8d7b-12977e46ad98 --- pjlib/build/Makefile | 302 ++-- pjlib/build/os-linux-kernel.mak | 94 +- pjlib/build/os-linux.mak | 72 +- pjlib/build/os-sunos.mak | 36 + pjlib/build/os-win32.mak | 54 +- pjlib/build/pjlib_samples.mak | 70 +- pjlib/docs/doxygen.css | 610 ++++---- pjlib/include/pj/addr_resolv.h | 152 +- pjlib/include/pj/array.h | 156 +- pjlib/include/pj/assert.h | 112 +- pjlib/include/pj/compat/assert.h | 76 +- pjlib/include/pj/compat/cc_gcc.h | 64 +- pjlib/include/pj/compat/cc_msvc.h | 80 +- pjlib/include/pj/compat/ctype.h | 84 +- pjlib/include/pj/compat/errno.h | 53 +- pjlib/include/pj/compat/high_precision.h | 168 +- pjlib/include/pj/compat/m_alpha.h | 46 +- pjlib/include/pj/compat/m_i386.h | 52 +- pjlib/include/pj/compat/m_m68k.h | 42 +- pjlib/include/pj/compat/m_sparc.h | 21 + pjlib/include/pj/compat/malloc.h | 50 +- pjlib/include/pj/compat/os_linux.h | 138 +- pjlib/include/pj/compat/os_linux_kernel.h | 172 +-- pjlib/include/pj/compat/os_palmos.h | 108 +- pjlib/include/pj/compat/os_sunos.h | 56 + pjlib/include/pj/compat/os_win32.h | 144 +- pjlib/include/pj/compat/rand.h | 130 +- pjlib/include/pj/compat/setjmp.h | 178 +-- pjlib/include/pj/compat/size_t.h | 46 +- pjlib/include/pj/compat/socket.h | 258 ++-- pjlib/include/pj/compat/sprintf.h | 62 +- pjlib/include/pj/compat/stdarg.h | 40 +- pjlib/include/pj/compat/stdfileio.h | 40 +- pjlib/include/pj/compat/string.h | 82 +- pjlib/include/pj/compat/time.h | 50 +- pjlib/include/pj/compat/vsprintf.h | 52 +- pjlib/include/pj/config.h | 880 +++++------ pjlib/include/pj/ctype.h | 238 +-- pjlib/include/pj/doxygen.h | 1760 ++++++++++----------- pjlib/include/pj/equeue.h | 638 ++++---- pjlib/include/pj/errno.h | 498 +++--- pjlib/include/pj/except.h | 534 +++---- pjlib/include/pj/fifobuf.h | 54 +- pjlib/include/pj/guid.h | 150 +- pjlib/include/pj/hash.h | 280 ++-- pjlib/include/pj/ioqueue.h | 946 ++++++------ pjlib/include/pj/list.h | 434 +++--- pjlib/include/pj/list_i.h | 202 +-- pjlib/include/pj/lock.h | 272 ++-- pjlib/include/pj/log.h | 608 ++++---- pjlib/include/pj/md5.h | 184 +-- pjlib/include/pj/os.h | 1813 +++++++++++----------- pjlib/include/pj/pool.h | 1140 +++++++------- pjlib/include/pj/pool_i.h | 148 +- pjlib/include/pj/rand.h | 120 +- pjlib/include/pj/rbtree.h | 386 ++--- pjlib/include/pj/scanner.h | 908 +++++------ pjlib/include/pj/sock.h | 1354 ++++++++-------- pjlib/include/pj/sock_select.h | 282 ++-- pjlib/include/pj/string.h | 1030 ++++++------- pjlib/include/pj/string_i.h | 324 ++-- pjlib/include/pj/stun.h | 246 +-- pjlib/include/pj/timer.h | 474 +++--- pjlib/include/pj/types.h | 836 +++++----- pjlib/include/pj/xml.h | 310 ++-- pjlib/include/pjlib.h | 78 +- pjlib/src/pj/addr_resolv_linux_kernel.c | 28 +- pjlib/src/pj/addr_resolv_sock.c | 88 +- pjlib/src/pj/array.c | 126 +- pjlib/src/pj/compat/longjmp_i386.S | 84 +- pjlib/src/pj/compat/setjmp_i386.S | 122 +- pjlib/src/pj/compat/sigjmp.c | 42 +- pjlib/src/pj/compat/string.c | 66 +- pjlib/src/pj/config.c | 80 +- pjlib/src/pj/equeue_winnt.c | 26 +- pjlib/src/pj/errno.c | 214 +-- pjlib/src/pj/except.c | 296 ++-- pjlib/src/pj/extra-exports.c | 76 +- pjlib/src/pj/fifobuf.c | 364 ++--- pjlib/src/pj/guid.c | 38 +- pjlib/src/pj/guid_simple.c | 120 +- pjlib/src/pj/guid_win32.c | 122 +- pjlib/src/pj/hash.c | 504 +++--- pjlib/src/pj/ioqueue_dummy.c | 372 ++--- pjlib/src/pj/ioqueue_epoll.c | 1704 ++++++++++---------- pjlib/src/pj/ioqueue_linux_kernel.c | 300 ++-- pjlib/src/pj/ioqueue_select.c | 1911 +++++++++++------------ pjlib/src/pj/ioqueue_winnt.c | 1704 ++++++++++---------- pjlib/src/pj/list.c | 36 +- pjlib/src/pj/lock.c | 380 ++--- pjlib/src/pj/log.c | 434 +++--- pjlib/src/pj/log_writer_printk.c | 40 +- pjlib/src/pj/log_writer_stdout.c | 132 +- pjlib/src/pj/md5.c | 808 +++++----- pjlib/src/pj/os_core_linux_kernel.c | 1371 ++++++++--------- pjlib/src/pj/os_core_unix.c | 2391 +++++++++++++++-------------- pjlib/src/pj/os_core_win32.c | 2373 ++++++++++++++-------------- pjlib/src/pj/os_error_linux_kernel.c | 146 +- pjlib/src/pj/os_error_unix.c | 104 +- pjlib/src/pj/os_error_win32.c | 322 ++-- pjlib/src/pj/os_time_ansi.c | 130 +- pjlib/src/pj/os_time_linux_kernel.c | 116 +- pjlib/src/pj/os_timestamp_common.c | 258 ++-- pjlib/src/pj/os_timestamp_linux.c | 274 ++-- pjlib/src/pj/os_timestamp_linux_kernel.c | 140 +- pjlib/src/pj/os_timestamp_win32.c | 76 +- pjlib/src/pj/pool.c | 530 +++---- pjlib/src/pj/pool_caching.c | 420 ++--- pjlib/src/pj/pool_dbg_win32.c | 452 +++--- pjlib/src/pj/pool_policy_kmalloc.c | 108 +- pjlib/src/pj/pool_policy_malloc.c | 116 +- pjlib/src/pj/rand.c | 58 +- pjlib/src/pj/rbtree.c | 832 +++++----- pjlib/src/pj/scanner.c | 1112 +++++++------- pjlib/src/pj/sock_bsd.c | 1144 +++++++------- pjlib/src/pj/sock_linux_kernel.c | 1498 +++++++++--------- pjlib/src/pj/sock_select.c | 206 +-- pjlib/src/pj/string.c | 248 +-- pjlib/src/pj/stun.c | 236 +-- pjlib/src/pj/stun_client.c | 540 +++---- pjlib/src/pj/symbols.c | 808 +++++----- pjlib/src/pj/timer.c | 1008 ++++++------ pjlib/src/pj/types.c | 72 +- pjlib/src/pj/xml.c | 784 +++++----- pjlib/src/pjlib-samples/except.c | 158 +- pjlib/src/pjlib-samples/list.c | 132 +- pjlib/src/pjlib-samples/log.c | 72 +- pjlib/src/pjlib-test/atomic.c | 188 +-- pjlib/src/pjlib-test/echo_clt.c | 544 +++---- pjlib/src/pjlib-test/echo_srv.c | 662 ++++---- pjlib/src/pjlib-test/errno.c | 324 ++-- pjlib/src/pjlib-test/exception.c | 312 ++-- pjlib/src/pjlib-test/fifobuf.c | 200 +-- pjlib/src/pjlib-test/ioq_perf.c | 932 +++++------ pjlib/src/pjlib-test/ioq_tcp.c | 948 ++++++------ pjlib/src/pjlib-test/ioq_udp.c | 1328 ++++++++-------- pjlib/src/pjlib-test/list.c | 418 ++--- pjlib/src/pjlib-test/main.c | 163 +- pjlib/src/pjlib-test/main_mod.c | 66 +- pjlib/src/pjlib-test/mutex.c | 328 ++-- pjlib/src/pjlib-test/os.c | 20 +- pjlib/src/pjlib-test/pool.c | 328 ++-- pjlib/src/pjlib-test/pool_perf.c | 268 ++-- pjlib/src/pjlib-test/rand.c | 86 +- pjlib/src/pjlib-test/rbtree.c | 300 ++-- pjlib/src/pjlib-test/select.c | 416 ++--- pjlib/src/pjlib-test/sleep.c | 396 ++--- pjlib/src/pjlib-test/sock.c | 918 +++++------ pjlib/src/pjlib-test/sock_perf.c | 366 ++--- pjlib/src/pjlib-test/string.c | 336 ++-- pjlib/src/pjlib-test/test.c | 392 ++--- pjlib/src/pjlib-test/test.h | 180 +-- pjlib/src/pjlib-test/thread.c | 580 +++---- pjlib/src/pjlib-test/timer.c | 338 ++-- pjlib/src/pjlib-test/timestamp.c | 283 ++-- pjlib/src/pjlib-test/udp_echo_srv_sync.c | 336 ++-- pjlib/src/pjlib-test/util.c | 258 ++-- pjlib/src/pjlib-test/xml.c | 254 +-- 158 files changed, 31105 insertions(+), 30892 deletions(-) create mode 100644 pjlib/build/os-sunos.mak create mode 100644 pjlib/include/pj/compat/m_sparc.h create mode 100644 pjlib/include/pj/compat/os_sunos.h (limited to 'pjlib') diff --git a/pjlib/build/Makefile b/pjlib/build/Makefile index 7bffdc99..21b2d387 100644 --- a/pjlib/build/Makefile +++ b/pjlib/build/Makefile @@ -1,151 +1,151 @@ -# -# Include host/target/compiler selection. -# This will export CC_NAME, MACHINE_NAME, OS_NAME, and HOST_NAME variables. -# -include ../../build.mak - -# -# Include global compiler specific definitions -# -include ../../build/cc-$(CC_NAME).mak - -# -# (Optionally) Include compiler specific configuration that is -# specific to this project. This configuration file is -# located in this directory. -# --include cc-$(CC_NAME).mak - -# -# Include global machine specific definitions -# -include ../../build/m-$(MACHINE_NAME).mak --include m-$(MACHINE_NAME).mak - -# -# Include target OS specific definitions -# -include ../../build/os-$(OS_NAME).mak - -# -# (Optionally) Include target OS specific configuration that is -# specific to this project. This configuration file is -# located in this directory. -# --include os-$(OS_NAME).mak - -# -# Include host specific definitions -# -include ../../build/host-$(HOST_NAME).mak - -# -# (Optionally) Include host specific configuration that is -# specific to this project. This configuration file is -# located in this directory. -# --include host-$(HOST_NAME).mak - -# -# Include global user configuration, if any -# --include ../../user.mak - - -RULES_MAK := ../../build/rules.mak - - -export PJLIB_LIB := ../lib/libpj-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT) - -############################################################################### -# Gather all flags. -# -export _CFLAGS := $(CC_CFLAGS) $(OS_CFLAGS) $(HOST_CFLAGS) $(M_CFLAGS) \ - $(CFLAGS) $(CC_INC)../include -export _CXXFLAGS:= $(_CFLAGS) $(CC_CXXFLAGS) $(OS_CXXFLAGS) $(M_CXXFLAGS) \ - $(HOST_CXXFLAGS) $(CXXFLAGS) -export _LDFLAGS := $(subst /,$(HOST_PSEP),$(PJLIB_LIB)) \ - $(CC_LDFLAGS) $(OS_LDFLAGS) $(M_LDFLAGS) $(HOST_LDFLAGS) \ - $(LDFLAGS) - -############################################################################### -# Defines for building PJLIB library -# -export PJLIB_SRCDIR = ../src/pj -export PJLIB_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \ - array.o config.o errno.o except.o fifobuf.o guid.o \ - hash.o list.o lock.o log.o \ - md5.o pool.o pool_caching.o rand.o \ - rbtree.o scanner.o string.o stun.o stun_client.o timer.o \ - types.o xml.o symbols.o -export PJLIB_CFLAGS += $(_CFLAGS) - -############################################################################### -# Defines for building test application -# -export TEST_SRCDIR = ../src/pjlib-test -export TEST_OBJS += atomic.o echo_clt.o echo_srv.o errno.o exception.o \ - fifobuf.o \ - ioq_perf.o ioq_udp.o ioq_tcp.o \ - list.o mutex.o os.o pool.o pool_perf.o rand.o rbtree.o \ - select.o sleep.o sock.o sock_perf.o \ - string.o test.o thread.o timer.o timestamp.o \ - udp_echo_srv_sync.o \ - util.o xml.o -export TEST_CFLAGS += $(_CFLAGS) -export TEST_LDFLAGS += $(_LDFLAGS) -export TEST_EXE := ../bin/pjlib-test-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(HOST_EXE) - - -export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT - -############################################################################### -# Main entry -# -# $(TARGET) is defined in os-$(OS_NAME).mak file in current directory. -# - -all: $(TARGETS) - -doc: - cd .. && doxygen docs/doxygen.cfg - -print: - $(MAKE) -f $(RULES_MAK) APP=PJLIB app=pjlib print_lib - $(MAKE) -f $(RULES_MAK) APP=TEST app=pjlib-test print_bin - -depend: - $(MAKE) -f $(RULES_MAK) APP=PJLIB app=pjlib depend - $(MAKE) -f $(RULES_MAK) APP=TEST app=pjlib-test depend - echo '$(TEST_EXE): $(PJLIB_LIB)' >> .pjlib-test-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME).depend - - -.PHONY: dep depend pjlib pjlib-test clean realclean distclean - -dep: depend - -pjlib: - $(MAKE) -f $(RULES_MAK) APP=PJLIB app=pjlib $(PJLIB_LIB) - -pjlib-test: - $(MAKE) -f $(RULES_MAK) APP=TEST app=pjlib-test $(TEST_EXE) - -.PHONY: ../lib/pjlib.ko -../lib/pjlib.ko: - echo Making $@ - $(MAKE) -f $(RULES_MAK) APP=PJLIB app=pjlib $@ - -.PHONY: ../lib/pjlib-test.ko -../lib/pjlib-test.ko: - $(MAKE) -f $(RULES_MAK) APP=TEST app=pjlib-test $@ - -clean: - $(MAKE) -f $(RULES_MAK) APP=PJLIB app=pjlib clean - $(MAKE) -f $(RULES_MAK) APP=TEST app=pjlib-test clean - -realclean: - $(MAKE) -f $(RULES_MAK) APP=PJLIB app=pjlib realclean - $(MAKE) -f $(RULES_MAK) APP=TEST app=pjlib-test realclean - -distclean: realclean - +# +# Include host/target/compiler selection. +# This will export CC_NAME, MACHINE_NAME, OS_NAME, and HOST_NAME variables. +# +include ../../build.mak + +# +# Include global compiler specific definitions +# +include ../../build/cc-$(CC_NAME).mak + +# +# (Optionally) Include compiler specific configuration that is +# specific to this project. This configuration file is +# located in this directory. +# +-include cc-$(CC_NAME).mak + +# +# Include global machine specific definitions +# +include ../../build/m-$(MACHINE_NAME).mak +-include m-$(MACHINE_NAME).mak + +# +# Include target OS specific definitions +# +include ../../build/os-$(OS_NAME).mak + +# +# (Optionally) Include target OS specific configuration that is +# specific to this project. This configuration file is +# located in this directory. +# +-include os-$(OS_NAME).mak + +# +# Include host specific definitions +# +include ../../build/host-$(HOST_NAME).mak + +# +# (Optionally) Include host specific configuration that is +# specific to this project. This configuration file is +# located in this directory. +# +-include host-$(HOST_NAME).mak + +# +# Include global user configuration, if any +# +-include ../../user.mak + + +RULES_MAK := ../../build/rules.mak + + +export PJLIB_LIB := ../lib/libpj-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(LIBEXT) + +############################################################################### +# Gather all flags. +# +export _CFLAGS := -O2 $(CC_CFLAGS) $(OS_CFLAGS) $(HOST_CFLAGS) $(M_CFLAGS) \ + $(CFLAGS) $(CC_INC)../include +export _CXXFLAGS:= $(_CFLAGS) $(CC_CXXFLAGS) $(OS_CXXFLAGS) $(M_CXXFLAGS) \ + $(HOST_CXXFLAGS) $(CXXFLAGS) +export _LDFLAGS := $(subst /,$(HOST_PSEP),$(PJLIB_LIB)) \ + $(CC_LDFLAGS) $(OS_LDFLAGS) $(M_LDFLAGS) $(HOST_LDFLAGS) \ + $(LDFLAGS) + +############################################################################### +# Defines for building PJLIB library +# +export PJLIB_SRCDIR = ../src/pj +export PJLIB_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \ + array.o config.o errno.o except.o fifobuf.o guid.o \ + hash.o list.o lock.o log.o \ + md5.o pool.o pool_caching.o rand.o \ + rbtree.o scanner.o string.o stun.o stun_client.o timer.o \ + types.o xml.o symbols.o +export PJLIB_CFLAGS += $(_CFLAGS) + +############################################################################### +# Defines for building test application +# +export TEST_SRCDIR = ../src/pjlib-test +export TEST_OBJS += atomic.o echo_clt.o echo_srv.o errno.o exception.o \ + fifobuf.o \ + ioq_perf.o ioq_udp.o ioq_tcp.o \ + list.o mutex.o os.o pool.o pool_perf.o rand.o rbtree.o \ + select.o sleep.o sock.o sock_perf.o \ + string.o test.o thread.o timer.o timestamp.o \ + udp_echo_srv_sync.o \ + util.o xml.o +export TEST_CFLAGS += $(_CFLAGS) +export TEST_LDFLAGS += $(_LDFLAGS) +export TEST_EXE := ../bin/pjlib-test-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME)$(HOST_EXE) + + +export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT + +############################################################################### +# Main entry +# +# $(TARGET) is defined in os-$(OS_NAME).mak file in current directory. +# + +all: $(TARGETS) + +doc: + cd .. && doxygen docs/doxygen.cfg + +print: + $(MAKE) -f $(RULES_MAK) APP=PJLIB app=pjlib print_lib + $(MAKE) -f $(RULES_MAK) APP=TEST app=pjlib-test print_bin + +depend: + $(MAKE) -f $(RULES_MAK) APP=PJLIB app=pjlib depend + $(MAKE) -f $(RULES_MAK) APP=TEST app=pjlib-test depend + echo '$(TEST_EXE): $(PJLIB_LIB)' >> .pjlib-test-$(MACHINE_NAME)-$(OS_NAME)-$(CC_NAME).depend + + +.PHONY: dep depend pjlib pjlib-test clean realclean distclean + +dep: depend + +pjlib: + $(MAKE) -f $(RULES_MAK) APP=PJLIB app=pjlib $(PJLIB_LIB) + +pjlib-test: + $(MAKE) -f $(RULES_MAK) APP=TEST app=pjlib-test $(TEST_EXE) + +.PHONY: ../lib/pjlib.ko +../lib/pjlib.ko: + echo Making $@ + $(MAKE) -f $(RULES_MAK) APP=PJLIB app=pjlib $@ + +.PHONY: ../lib/pjlib-test.ko +../lib/pjlib-test.ko: + $(MAKE) -f $(RULES_MAK) APP=TEST app=pjlib-test $@ + +clean: + $(MAKE) -f $(RULES_MAK) APP=PJLIB app=pjlib clean + $(MAKE) -f $(RULES_MAK) APP=TEST app=pjlib-test clean + +realclean: + $(MAKE) -f $(RULES_MAK) APP=PJLIB app=pjlib realclean + $(MAKE) -f $(RULES_MAK) APP=TEST app=pjlib-test realclean + +distclean: realclean + diff --git a/pjlib/build/os-linux-kernel.mak b/pjlib/build/os-linux-kernel.mak index 1503156a..934c8898 100644 --- a/pjlib/build/os-linux-kernel.mak +++ b/pjlib/build/os-linux-kernel.mak @@ -1,47 +1,47 @@ -# -# OS specific configuration for Linux Kernel module target. -# - -# -# PJLIB_OBJS specified here are object files to be included in PJLIB -# (the library) for this specific operating system. Object files common -# to all operating systems should go in Makefile instead. -# -export PJLIB_OBJS += compat/sigjmp.o compat/setjmp_i386.o \ - compat/longjmp_i386.o compat/string.o \ - addr_resolv_linux_kernel.o \ - guid_simple.o \ - log_writer_printk.o pool_policy_kmalloc.o \ - os_error_linux_kernel.o os_core_linux_kernel.o \ - os_time_linux_kernel.o os_timestamp_common.o \ - os_timestamp_linux_kernel.o \ - sock_linux_kernel.o sock_select.o - -# For IOQueue, we can use either epoll or select -export PJLIB_OBJS += ioqueue_epoll.o -#export PJLIB_OBJS += ioqueue_select.o - -# -# TEST_OBJS are operating system specific object files to be included in -# the test application. -# -export TEST_OBJS += main_mod.o - -# -# Additional CFLAGS -# -export TEST_CFLAGS += -msoft-float - -# -# Additional LD_FLAGS for this target. -# -export TEST_LDFLAGS += -lgcc - - -# -# TARGETS are make targets in the Makefile, to be executed for this given -# operating system. -# -export TARGETS := ../lib/pjlib.ko ../lib/pjlib-test.ko - - +# +# OS specific configuration for Linux Kernel module target. +# + +# +# PJLIB_OBJS specified here are object files to be included in PJLIB +# (the library) for this specific operating system. Object files common +# to all operating systems should go in Makefile instead. +# +export PJLIB_OBJS += compat/sigjmp.o compat/setjmp_i386.o \ + compat/longjmp_i386.o compat/string.o \ + addr_resolv_linux_kernel.o \ + guid_simple.o \ + log_writer_printk.o pool_policy_kmalloc.o \ + os_error_linux_kernel.o os_core_linux_kernel.o \ + os_time_linux_kernel.o os_timestamp_common.o \ + os_timestamp_linux_kernel.o \ + sock_linux_kernel.o sock_select.o + +# For IOQueue, we can use either epoll or select +export PJLIB_OBJS += ioqueue_epoll.o +#export PJLIB_OBJS += ioqueue_select.o + +# +# TEST_OBJS are operating system specific object files to be included in +# the test application. +# +export TEST_OBJS += main_mod.o + +# +# Additional CFLAGS +# +export TEST_CFLAGS += -msoft-float + +# +# Additional LD_FLAGS for this target. +# +export TEST_LDFLAGS += -lgcc + + +# +# TARGETS are make targets in the Makefile, to be executed for this given +# operating system. +# +export TARGETS := ../lib/pjlib.ko ../lib/pjlib-test.ko + + diff --git a/pjlib/build/os-linux.mak b/pjlib/build/os-linux.mak index 41dff534..fd9fc307 100644 --- a/pjlib/build/os-linux.mak +++ b/pjlib/build/os-linux.mak @@ -1,36 +1,36 @@ -# -# OS specific configuration for Linux OS target. -# - -# -# PJLIB_OBJS specified here are object files to be included in PJLIB -# (the library) for this specific operating system. Object files common -# to all operating systems should go in Makefile instead. -# -export PJLIB_OBJS += addr_resolv_sock.o guid_simple.o \ - log_writer_stdout.o os_core_unix.o \ - os_error_unix.o os_time_ansi.o \ - os_timestamp_common.o os_timestamp_linux.o \ - os_time_ansi.o \ - pool_policy_malloc.o sock_bsd.o sock_select.o - -export PJLIB_OBJS += ioqueue_select.o -#export PJLIB_OBJS += ioqueue_epoll.o - -# -# TEST_OBJS are operating system specific object files to be included in -# the test application. -# -export TEST_OBJS += main.o - -# -# Additional LDFLAGS for pjlib-test -# -export TEST_LDFLAGS += -lm - -# -# TARGETS are make targets in the Makefile, to be executed for this given -# operating system. -# -export TARGETS = pjlib pjlib-test - +# +# OS specific configuration for Linux OS target. +# + +# +# PJLIB_OBJS specified here are object files to be included in PJLIB +# (the library) for this specific operating system. Object files common +# to all operating systems should go in Makefile instead. +# +export PJLIB_OBJS += addr_resolv_sock.o guid_simple.o \ + log_writer_stdout.o os_core_unix.o \ + os_error_unix.o os_time_ansi.o \ + os_timestamp_common.o os_timestamp_linux.o \ + os_time_ansi.o \ + pool_policy_malloc.o sock_bsd.o sock_select.o + +export PJLIB_OBJS += ioqueue_select.o +#export PJLIB_OBJS += ioqueue_epoll.o + +# +# TEST_OBJS are operating system specific object files to be included in +# the test application. +# +export TEST_OBJS += main.o + +# +# Additional LDFLAGS for pjlib-test +# +export TEST_LDFLAGS += -lm + +# +# TARGETS are make targets in the Makefile, to be executed for this given +# operating system. +# +export TARGETS = pjlib pjlib-test + diff --git a/pjlib/build/os-sunos.mak b/pjlib/build/os-sunos.mak new file mode 100644 index 00000000..81ab64da --- /dev/null +++ b/pjlib/build/os-sunos.mak @@ -0,0 +1,36 @@ +# +# PJLIB OS specific configuration for SunOS target. +# + +# +# PJLIB_OBJS specified here are object files to be included in PJLIB +# (the library) for this specific operating system. Object files common +# to all operating systems should go in Makefile instead. +# +export PJLIB_OBJS += addr_resolv_sock.o guid_simple.o \ + log_writer_stdout.o os_core_unix.o \ + os_error_unix.o os_time_ansi.o \ + os_timestamp_common.o os_timestamp_linux.o \ + os_time_ansi.o \ + pool_policy_malloc.o sock_bsd.o sock_select.o + +export PJLIB_OBJS += ioqueue_select.o +#export PJLIB_OBJS += ioqueue_epoll.o + +# +# TEST_OBJS are operating system specific object files to be included in +# the test application. +# +export TEST_OBJS += main.o + +# +# Additional LDFLAGS for pjlib-test +# +export TEST_LDFLAGS += -lm + +# +# TARGETS are make targets in the Makefile, to be executed for this given +# operating system. +# +export TARGETS = pjlib pjlib-test + diff --git a/pjlib/build/os-win32.mak b/pjlib/build/os-win32.mak index fbe3a66c..7b236c6a 100644 --- a/pjlib/build/os-win32.mak +++ b/pjlib/build/os-win32.mak @@ -1,27 +1,27 @@ -# -# OS specific configuration for Win32 OS target. -# - -# -# PJLIB_OBJS specified here are object files to be included in PJLIB -# (the library) for this specific operating system. Object files common -# to all operating systems should go in Makefile instead. -# -export PJLIB_OBJS += addr_resolv_sock.o guid_win32.o ioqueue_winnt.o \ - log_writer_stdout.o os_core_win32.o \ - os_error_win32.o os_time_ansi.o os_timestamp_common.o \ - os_timestamp_win32.o \ - pool_policy_malloc.o sock_bsd.o sock_select.o - -# -# TEST_OBJS are operating system specific object files to be included in -# the test application. -# -export TEST_OBJS += main.o - -# -# TARGETS are make targets in the Makefile, to be executed for this given -# operating system. -# -export TARGETS = pjlib pjlib-test - +# +# OS specific configuration for Win32 OS target. +# + +# +# PJLIB_OBJS specified here are object files to be included in PJLIB +# (the library) for this specific operating system. Object files common +# to all operating systems should go in Makefile instead. +# +export PJLIB_OBJS += addr_resolv_sock.o guid_win32.o ioqueue_winnt.o \ + log_writer_stdout.o os_core_win32.o \ + os_error_win32.o os_time_ansi.o os_timestamp_common.o \ + os_timestamp_win32.o \ + pool_policy_malloc.o sock_bsd.o sock_select.o + +# +# TEST_OBJS are operating system specific object files to be included in +# the test application. +# +export TEST_OBJS += main.o + +# +# TARGETS are make targets in the Makefile, to be executed for this given +# operating system. +# +export TARGETS = pjlib pjlib-test + diff --git a/pjlib/build/pjlib_samples.mak b/pjlib/build/pjlib_samples.mak index 21b42072..322cc212 100644 --- a/pjlib/build/pjlib_samples.mak +++ b/pjlib/build/pjlib_samples.mak @@ -1,35 +1,35 @@ -OUTDIR=.\output\pjlib-samples-i386-win32-vc6-$(MODE) - -SRCDIR=../src/pjlib-samples - -SAMPLES=$(OUTDIR)/except.exe \ - $(OUTDIR)/log.exe \ - $(OUTDIR)/list.exe \ - -!IF "$(MODE)" == "debug" -MODE_CFLAGS=/MTd -!ELSE -MODE_CFLAGS=/MT -!ENDIF - -CFLAGS=/nologo /W4 $(MODE_CFLAGS) /DPJ_WIN32=1 /DPJ_M_I386=1 /I../include - -PJLIB=../lib/pjlib-i386-win32-vc6-$(MODE).lib - -DEPEND=$(PJLIB) -LIBS=netapi32.lib mswsock.lib ws2_32.lib ole32.lib -CL=cl.exe - -all: "$(OUTDIR)" $(SAMPLES) - -$(SAMPLES): "$(SRCDIR)/$(@B).c" $(DEPEND) - $(CL) /Fe$@ \ - /Fo$(@R).obj \ - $(CFLAGS) \ - $** $(LIBS) - -"$(OUTDIR)" : - @IF NOT EXIST "$(OUTDIR)" MKDIR "$(OUTDIR)" - -clean : - @IF EXIST "$(OUTDIR)" DEL /Q "$(OUTDIR)\*.*" && RMDIR "$(OUTDIR)" +OUTDIR=.\output\pjlib-samples-i386-win32-vc6-$(MODE) + +SRCDIR=../src/pjlib-samples + +SAMPLES=$(OUTDIR)/except.exe \ + $(OUTDIR)/log.exe \ + $(OUTDIR)/list.exe \ + +!IF "$(MODE)" == "debug" +MODE_CFLAGS=/MTd +!ELSE +MODE_CFLAGS=/MT +!ENDIF + +CFLAGS=/nologo /W4 $(MODE_CFLAGS) /DPJ_WIN32=1 /DPJ_M_I386=1 /I../include + +PJLIB=../lib/pjlib-i386-win32-vc6-$(MODE).lib + +DEPEND=$(PJLIB) +LIBS=netapi32.lib mswsock.lib ws2_32.lib ole32.lib +CL=cl.exe + +all: "$(OUTDIR)" $(SAMPLES) + +$(SAMPLES): "$(SRCDIR)/$(@B).c" $(DEPEND) + $(CL) /Fe$@ \ + /Fo$(@R).obj \ + $(CFLAGS) \ + $** $(LIBS) + +"$(OUTDIR)" : + @IF NOT EXIST "$(OUTDIR)" MKDIR "$(OUTDIR)" + +clean : + @IF EXIST "$(OUTDIR)" DEL /Q "$(OUTDIR)\*.*" && RMDIR "$(OUTDIR)" diff --git a/pjlib/docs/doxygen.css b/pjlib/docs/doxygen.css index accad141..015c0c27 100644 --- a/pjlib/docs/doxygen.css +++ b/pjlib/docs/doxygen.css @@ -1,305 +1,305 @@ -BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { - font-family: Geneva, Arial, Helvetica, sans-serif; -} -BODY,TD { - font-size: 80%; -} -CODE { - font-size: 120%; - font-family: monospace; -} -.fragment, pre { - font-size: 110%; - font-family: monospace; -} -H1 { - text-align: center; - font-size: 240%; -} -H2 { - font-size: 200%; - margin-top : 60px; -} -H3 { - font-size: 160%; -} -H4 { - font-size: 120%; -} -CAPTION { font-weight: bold } -DIV.qindex { - width: 100%; - background-color: #eeeeff; - border: 1px solid #b0b0b0; - text-align: center; - margin: 2px; - padding: 2px; - line-height: 140%; -} -DIV.nav { - width: 100%; - background-color: #eeeeff; - border: 1px solid #b0b0b0; - text-align: center; - margin: 2px; - padding: 2px; - line-height: 140%; -} -A.qindex { - text-decoration: none; - font-size: 120%; - color: #1A419D; -} -A.qindex:visited { - text-decoration: none; - color: #1A419D -} -A.qindex:hover { - text-decoration: none; - background-color: #ddddff; -} -A.qindexHL { - text-decoration: none; - font-weight: bold; - background-color: #6666cc; - color: #ffffff; - border: 1px double #9295C2; -} -A.qindexHL:hover { - text-decoration: none; - background-color: #6666cc; - color: #ffffff; -} -A.qindexHL:visited { text-decoration: none; background-color: #6666cc; color: #ffffff } -A.el { text-decoration: none; font-weight: bold } -A.elRef { font-weight: bold } -A.code:link { text-decoration: none; font-weight: normal; color: #0000FF; } -A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF} -A.codeRef:link { font-weight: normal; color: #0000FF} -A.codeRef:visited { font-weight: normal; color: #0000FF} -A:hover { text-decoration: none; background-color: #f2f2ff } -DL.el { margin-left: -1cm } -PRE.fragment { - border: 1px solid #CCCCCC; - background-color: #f5f5f5; - margin-top: 4px; - margin-bottom: 4px; - margin-left: 2px; - margin-right: 8px; - padding-left: 6px; - padding-right: 6px; - padding-top: 4px; - padding-bottom: 4px; -} -DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } -TD.md { background-color: #F4F4FB; font-weight: bold; } -TD.mdPrefix { - background-color: #F4F4FB; - color: #606060; - font-size: 80%; -} -TD.mdname1 { background-color: #F4F4FB; font-weight: bold; color: #602020; } -TD.mdname { background-color: #F4F4FB; font-weight: bold; color: #602020; width: 600px; } -DIV.groupHeader { - margin-left: 16px; - margin-top: 12px; - margin-bottom: 6px; - font-weight: bold; -} -DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% } -BODY { - background: white; - color: black; - margin-right: 20px; - margin-left: 20px; -} -TD.indexkey { - background-color: #eeeeff; - font-weight: bold; - padding-right : 10px; - padding-top : 2px; - padding-left : 10px; - padding-bottom : 2px; - margin-left : 0px; - margin-right : 0px; - margin-top : 2px; - margin-bottom : 2px; - border: 1px solid #CCCCCC; -} -TD.indexvalue { - background-color: #eeeeff; - font-style: italic; - padding-right : 10px; - padding-top : 2px; - padding-left : 10px; - padding-bottom : 2px; - margin-left : 0px; - margin-right : 0px; - margin-top : 2px; - margin-bottom : 2px; - border: 1px solid #CCCCCC; -} -TR.memlist { - background-color: #f0f0f0; -} -P.formulaDsp { text-align: center; } -IMG.formulaDsp { } -IMG.formulaInl { vertical-align: middle; } -SPAN.keyword { color: #008000 } -SPAN.keywordtype { color: #604020 } -SPAN.keywordflow { color: #e08000 } -SPAN.comment { color: #800000 } -SPAN.preprocessor { color: #806020 } -SPAN.stringliteral { color: #002080 } -SPAN.charliteral { color: #008080 } -.mdTable { - border: 1px solid #868686; - background-color: #F4F4FB; -} -.mdRow { - padding: 8px 10px; -} -.mdescLeft { - padding: 0px 8px 4px 8px; - font-size: 80%; - font-style: italic; - background-color: #FAFAFA; - border-top: 1px none #E0E0E0; - border-right: 1px none #E0E0E0; - border-bottom: 1px none #E0E0E0; - border-left: 1px none #E0E0E0; - margin: 0px; -} -.mdescRight { - padding: 0px 8px 4px 8px; - font-size: 80%; - font-style: italic; - background-color: #FAFAFA; - border-top: 1px none #E0E0E0; - border-right: 1px none #E0E0E0; - border-bottom: 1px none #E0E0E0; - border-left: 1px none #E0E0E0; - margin: 0px; -} -.memItemLeft { - padding: 1px 0px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: solid; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - background-color: #FAFAFA; - font-size: 80%; -} -.memItemRight { - padding: 1px 8px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: solid; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - background-color: #FAFAFA; - font-size: 80%; -} -.memTemplItemLeft { - padding: 1px 0px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: none; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - background-color: #FAFAFA; - font-size: 80%; -} -.memTemplItemRight { - padding: 1px 8px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: none; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - background-color: #FAFAFA; - font-size: 80%; -} -.memTemplParams { - padding: 1px 0px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: solid; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - color: #606060; - background-color: #FAFAFA; - font-size: 80%; -} -.search { color: #003399; - font-weight: bold; -} -FORM.search { - margin-bottom: 0px; - margin-top: 0px; -} -INPUT.search { font-size: 75%; - color: #000080; - font-weight: normal; - background-color: #eeeeff; -} -TD.tiny { font-size: 75%; -} -a { - color: #252E78; -} -a:visited { - color: #3D2185; -} -.dirtab { padding: 4px; - border-collapse: collapse; - border: 1px solid #b0b0b0; -} -TH.dirtab { background: #eeeeff; - font-weight: bold; -} -HR { height: 1px; - border: none; - border-top: 1px solid black; -} +BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { + font-family: Geneva, Arial, Helvetica, sans-serif; +} +BODY,TD { + font-size: 80%; +} +CODE { + font-size: 120%; + font-family: monospace; +} +.fragment, pre { + font-size: 110%; + font-family: monospace; +} +H1 { + text-align: center; + font-size: 240%; +} +H2 { + font-size: 200%; + margin-top : 60px; +} +H3 { + font-size: 160%; +} +H4 { + font-size: 120%; +} +CAPTION { font-weight: bold } +DIV.qindex { + width: 100%; + background-color: #eeeeff; + border: 1px solid #b0b0b0; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +DIV.nav { + width: 100%; + background-color: #eeeeff; + border: 1px solid #b0b0b0; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +A.qindex { + text-decoration: none; + font-size: 120%; + color: #1A419D; +} +A.qindex:visited { + text-decoration: none; + color: #1A419D +} +A.qindex:hover { + text-decoration: none; + background-color: #ddddff; +} +A.qindexHL { + text-decoration: none; + font-weight: bold; + background-color: #6666cc; + color: #ffffff; + border: 1px double #9295C2; +} +A.qindexHL:hover { + text-decoration: none; + background-color: #6666cc; + color: #ffffff; +} +A.qindexHL:visited { text-decoration: none; background-color: #6666cc; color: #ffffff } +A.el { text-decoration: none; font-weight: bold } +A.elRef { font-weight: bold } +A.code:link { text-decoration: none; font-weight: normal; color: #0000FF; } +A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF} +A.codeRef:link { font-weight: normal; color: #0000FF} +A.codeRef:visited { font-weight: normal; color: #0000FF} +A:hover { text-decoration: none; background-color: #f2f2ff } +DL.el { margin-left: -1cm } +PRE.fragment { + border: 1px solid #CCCCCC; + background-color: #f5f5f5; + margin-top: 4px; + margin-bottom: 4px; + margin-left: 2px; + margin-right: 8px; + padding-left: 6px; + padding-right: 6px; + padding-top: 4px; + padding-bottom: 4px; +} +DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } +TD.md { background-color: #F4F4FB; font-weight: bold; } +TD.mdPrefix { + background-color: #F4F4FB; + color: #606060; + font-size: 80%; +} +TD.mdname1 { background-color: #F4F4FB; font-weight: bold; color: #602020; } +TD.mdname { background-color: #F4F4FB; font-weight: bold; color: #602020; width: 600px; } +DIV.groupHeader { + margin-left: 16px; + margin-top: 12px; + margin-bottom: 6px; + font-weight: bold; +} +DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% } +BODY { + background: white; + color: black; + margin-right: 20px; + margin-left: 20px; +} +TD.indexkey { + background-color: #eeeeff; + font-weight: bold; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TD.indexvalue { + background-color: #eeeeff; + font-style: italic; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TR.memlist { + background-color: #f0f0f0; +} +P.formulaDsp { text-align: center; } +IMG.formulaDsp { } +IMG.formulaInl { vertical-align: middle; } +SPAN.keyword { color: #008000 } +SPAN.keywordtype { color: #604020 } +SPAN.keywordflow { color: #e08000 } +SPAN.comment { color: #800000 } +SPAN.preprocessor { color: #806020 } +SPAN.stringliteral { color: #002080 } +SPAN.charliteral { color: #008080 } +.mdTable { + border: 1px solid #868686; + background-color: #F4F4FB; +} +.mdRow { + padding: 8px 10px; +} +.mdescLeft { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.mdescRight { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.memItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplParams { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + color: #606060; + background-color: #FAFAFA; + font-size: 80%; +} +.search { color: #003399; + font-weight: bold; +} +FORM.search { + margin-bottom: 0px; + margin-top: 0px; +} +INPUT.search { font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #eeeeff; +} +TD.tiny { font-size: 75%; +} +a { + color: #252E78; +} +a:visited { + color: #3D2185; +} +.dirtab { padding: 4px; + border-collapse: collapse; + border: 1px solid #b0b0b0; +} +TH.dirtab { background: #eeeeff; + font-weight: bold; +} +HR { height: 1px; + border: none; + border-top: 1px solid black; +} diff --git a/pjlib/include/pj/addr_resolv.h b/pjlib/include/pj/addr_resolv.h index 2daf0733..9b466918 100644 --- a/pjlib/include/pj/addr_resolv.h +++ b/pjlib/include/pj/addr_resolv.h @@ -1,76 +1,76 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/addr_resolv.h 2 10/14/05 12:25a Bennylp $ */ - -#ifndef __PJ_ADDR_RESOLV_H__ -#define __PJ_ADDR_RESOLV_H__ - -/** - * @file addr_resolv.h - * @brief Address resolve (pj_gethostbyname()). - */ - -#include - -PJ_BEGIN_DECL - -/** - * @defgroup pj_addr_resolve Address Resolution - * @ingroup PJ_IO - * @{ - * - * This module provides function to resolve Internet address of the - * specified host name. To resolve a particular host name, application - * can just call #pj_gethostbyname(). - * - * Example: - *
- *   ...
- *   pj_hostent he;
- *   pj_status_t rc;
- *   pj_str_t host = pj_str("host.example.com");
- *   
- *   rc = pj_gethostbyname( &host, &he);
- *   if (rc != PJ_SUCCESS) {
- *      char errbuf[80];
- *      pj_strerror( rc, errbuf, sizeof(errbuf));
- *      PJ_LOG(2,("sample", "Unable to resolve host, error=%s", errbuf));
- *      return rc;
- *   }
- *
- *   // process address...
- *   addr.sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
- *   ...
- * 
- * - * It's pretty simple really... - */ - -/** This structure describes an Internet host address. */ -typedef struct pj_hostent -{ - char *h_name; /**< The official name of the host. */ - char **h_aliases; /**< Aliases list. */ - int h_addrtype; /**< Host address type. */ - int h_length; /**< Length of address. */ - char **h_addr_list; /**< List of addresses. */ -} pj_hostent; - -/** Shortcut to h_addr_list[0] */ -#define h_addr h_addr_list[0] - -/** - * This function fills the structure of type pj_hostent for a given host name. - * - * @param name Host name, or IPv4 or IPv6 address in standard dot notation. - * @param he The pj_hostent structure to be filled. - * - * @return PJ_SUCCESS, or the appropriate error codes. - */ -PJ_DECL(pj_status_t) pj_gethostbyname(const pj_str_t *name, pj_hostent *he); - - -/** @} */ - -PJ_END_DECL - -#endif /* __PJ_ADDR_RESOLV_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/addr_resolv.h 2 10/14/05 12:25a Bennylp $ */ + +#ifndef __PJ_ADDR_RESOLV_H__ +#define __PJ_ADDR_RESOLV_H__ + +/** + * @file addr_resolv.h + * @brief Address resolve (pj_gethostbyname()). + */ + +#include + +PJ_BEGIN_DECL + +/** + * @defgroup pj_addr_resolve Address Resolution + * @ingroup PJ_IO + * @{ + * + * This module provides function to resolve Internet address of the + * specified host name. To resolve a particular host name, application + * can just call #pj_gethostbyname(). + * + * Example: + *
+ *   ...
+ *   pj_hostent he;
+ *   pj_status_t rc;
+ *   pj_str_t host = pj_str("host.example.com");
+ *   
+ *   rc = pj_gethostbyname( &host, &he);
+ *   if (rc != PJ_SUCCESS) {
+ *      char errbuf[80];
+ *      pj_strerror( rc, errbuf, sizeof(errbuf));
+ *      PJ_LOG(2,("sample", "Unable to resolve host, error=%s", errbuf));
+ *      return rc;
+ *   }
+ *
+ *   // process address...
+ *   addr.sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
+ *   ...
+ * 
+ * + * It's pretty simple really... + */ + +/** This structure describes an Internet host address. */ +typedef struct pj_hostent +{ + char *h_name; /**< The official name of the host. */ + char **h_aliases; /**< Aliases list. */ + int h_addrtype; /**< Host address type. */ + int h_length; /**< Length of address. */ + char **h_addr_list; /**< List of addresses. */ +} pj_hostent; + +/** Shortcut to h_addr_list[0] */ +#define h_addr h_addr_list[0] + +/** + * This function fills the structure of type pj_hostent for a given host name. + * + * @param name Host name, or IPv4 or IPv6 address in standard dot notation. + * @param he The pj_hostent structure to be filled. + * + * @return PJ_SUCCESS, or the appropriate error codes. + */ +PJ_DECL(pj_status_t) pj_gethostbyname(const pj_str_t *name, pj_hostent *he); + + +/** @} */ + +PJ_END_DECL + +#endif /* __PJ_ADDR_RESOLV_H__ */ + diff --git a/pjlib/include/pj/array.h b/pjlib/include/pj/array.h index bdc83d9b..1e9e158b 100644 --- a/pjlib/include/pj/array.h +++ b/pjlib/include/pj/array.h @@ -1,78 +1,78 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/array.h 7 10/14/05 12:25a Bennylp $ */ -#ifndef __PJ_ARRAY_H__ -#define __PJ_ARRAY_H__ - -/** - * @file array.h - * @brief PJLIB Array helper. - */ -#include - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_ARRAY Array helper. - * @ingroup PJ_DS - * @{ - * - * This module provides helper to manipulate array of elements of any size. - * It provides most used array operations such as insert, erase, and search. - */ - -/** - * Insert value to the array at the given position, and rearrange the - * remaining nodes after the position. - * - * @param array the array. - * @param elem_size the size of the individual element. - * @param count the current number of elements in the array. - * @param pos the position where the new element is put. - * @param value the value to copy to the new element. - */ -PJ_DECL(void) pj_array_insert( void *array, - unsigned elem_size, - unsigned count, - unsigned pos, - const void *value); - -/** - * Erase a value from the array at given position, and rearrange the remaining - * elements post the erased element. - * - * @param array the array. - * @param elem_size the size of the individual element. - * @param count the current number of elements in the array. - * @param pos the index/position to delete. - */ -PJ_DECL(void) pj_array_erase( void *array, - unsigned elem_size, - unsigned count, - unsigned pos); - -/** - * Search the first value in the array according to matching function. - * - * @param array the array. - * @param elem_size the individual size of the element. - * @param count the number of elements. - * @param matching the matching function, which MUST return PJ_SUCCESS if - * the specified element match. - * @param result the pointer to the value found. - * - * @return PJ_SUCCESS if value is found, otherwise the error code. - */ -PJ_DECL(pj_status_t) pj_array_find( const void *array, - unsigned elem_size, - unsigned count, - pj_status_t (*matching)(const void *value), - void **result); - -/** - * @} - */ - -PJ_END_DECL - - -#endif /* __PJ_ARRAY_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/array.h 7 10/14/05 12:25a Bennylp $ */ +#ifndef __PJ_ARRAY_H__ +#define __PJ_ARRAY_H__ + +/** + * @file array.h + * @brief PJLIB Array helper. + */ +#include + +PJ_BEGIN_DECL + +/** + * @defgroup PJ_ARRAY Array helper. + * @ingroup PJ_DS + * @{ + * + * This module provides helper to manipulate array of elements of any size. + * It provides most used array operations such as insert, erase, and search. + */ + +/** + * Insert value to the array at the given position, and rearrange the + * remaining nodes after the position. + * + * @param array the array. + * @param elem_size the size of the individual element. + * @param count the current number of elements in the array. + * @param pos the position where the new element is put. + * @param value the value to copy to the new element. + */ +PJ_DECL(void) pj_array_insert( void *array, + unsigned elem_size, + unsigned count, + unsigned pos, + const void *value); + +/** + * Erase a value from the array at given position, and rearrange the remaining + * elements post the erased element. + * + * @param array the array. + * @param elem_size the size of the individual element. + * @param count the current number of elements in the array. + * @param pos the index/position to delete. + */ +PJ_DECL(void) pj_array_erase( void *array, + unsigned elem_size, + unsigned count, + unsigned pos); + +/** + * Search the first value in the array according to matching function. + * + * @param array the array. + * @param elem_size the individual size of the element. + * @param count the number of elements. + * @param matching the matching function, which MUST return PJ_SUCCESS if + * the specified element match. + * @param result the pointer to the value found. + * + * @return PJ_SUCCESS if value is found, otherwise the error code. + */ +PJ_DECL(pj_status_t) pj_array_find( const void *array, + unsigned elem_size, + unsigned count, + pj_status_t (*matching)(const void *value), + void **result); + +/** + * @} + */ + +PJ_END_DECL + + +#endif /* __PJ_ARRAY_H__ */ + diff --git a/pjlib/include/pj/assert.h b/pjlib/include/pj/assert.h index 74705509..96fe8394 100644 --- a/pjlib/include/pj/assert.h +++ b/pjlib/include/pj/assert.h @@ -1,56 +1,56 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/assert.h 4 10/14/05 12:25a Bennylp $ */ -#ifndef __PJ_ASSERT_H__ -#define __PJ_ASSERT_H__ - -/** - * @file assert.h - * @brief Assertion macro pj_assert(). - */ - -#include -#include - -/** - * @defgroup pj_assert Assertion Macro - * @ingroup PJ_MISC - * @{ - * - * Assertion and other helper macros for sanity checking. - */ - -/** - * @hideinitializer - * Check during debug build that an expression is true. If the expression - * computes to false during run-time, then the program will stop at the - * offending statements. - * For release build, this macro will not do anything. - * - * @param expr The expression to be evaluated. - */ -#define pj_assert(expr) assert(expr) - - -/** - * @hideinitializer - * If #PJ_ENABLE_EXTRA_CHECK is declared and non-zero, then - * #PJ_ASSERT_RETURN macro will evaluate the expression in @a expr during - * run-time. If the expression yields false, assertion will be triggered - * and the current function will return with the specified return value. - * - * If #PJ_ENABLE_EXTRA_CHECK is not declared or is zero, then no run-time - * checking will be performed. The macro simply evaluates to pj_assert(expr). - */ -#if defined(PJ_ENABLE_EXTRA_CHECK) && PJ_ENABLE_EXTRA_CHECK != 0 -# define PJ_ASSERT_RETURN(expr,retval) \ - do { \ - pj_assert(expr); \ - if (!(expr)) return retval; \ - } while (0) -#else -# define PJ_ASSERT_RETURN(expr,retval) pj_assert(expr) -#endif - -/** @} */ - -#endif /* __PJ_ASSERT_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/assert.h 4 10/14/05 12:25a Bennylp $ */ +#ifndef __PJ_ASSERT_H__ +#define __PJ_ASSERT_H__ + +/** + * @file assert.h + * @brief Assertion macro pj_assert(). + */ + +#include +#include + +/** + * @defgroup pj_assert Assertion Macro + * @ingroup PJ_MISC + * @{ + * + * Assertion and other helper macros for sanity checking. + */ + +/** + * @hideinitializer + * Check during debug build that an expression is true. If the expression + * computes to false during run-time, then the program will stop at the + * offending statements. + * For release build, this macro will not do anything. + * + * @param expr The expression to be evaluated. + */ +#define pj_assert(expr) assert(expr) + + +/** + * @hideinitializer + * If #PJ_ENABLE_EXTRA_CHECK is declared and non-zero, then + * #PJ_ASSERT_RETURN macro will evaluate the expression in @a expr during + * run-time. If the expression yields false, assertion will be triggered + * and the current function will return with the specified return value. + * + * If #PJ_ENABLE_EXTRA_CHECK is not declared or is zero, then no run-time + * checking will be performed. The macro simply evaluates to pj_assert(expr). + */ +#if defined(PJ_ENABLE_EXTRA_CHECK) && PJ_ENABLE_EXTRA_CHECK != 0 +# define PJ_ASSERT_RETURN(expr,retval) \ + do { \ + pj_assert(expr); \ + if (!(expr)) return retval; \ + } while (0) +#else +# define PJ_ASSERT_RETURN(expr,retval) pj_assert(expr) +#endif + +/** @} */ + +#endif /* __PJ_ASSERT_H__ */ + diff --git a/pjlib/include/pj/compat/assert.h b/pjlib/include/pj/compat/assert.h index c3df94e0..658a0a97 100644 --- a/pjlib/include/pj/compat/assert.h +++ b/pjlib/include/pj/compat/assert.h @@ -1,38 +1,38 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/compat/assert.h 3 9/22/05 10:31a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/assert.h $ - * - * 3 9/22/05 10:31a Bennylp - * Moving all *.h files to include/. - * - * 2 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_ASSERT_H__ -#define __PJ_COMPAT_ASSERT_H__ - -/** - * @file assert.h - * @brief Provides assert() macro. - */ - -#if defined(PJ_HAS_ASSERT_H) && PJ_HAS_ASSERT_H != 0 -# include - -#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0 -# define assert(expr) do { \ - if (!(expr)) \ - printk("!!ASSERTION FAILED: [%s:%d] \"" #expr "\"\n",\ - __FILE__, __LINE__); \ - } while (0) - -#else -# warning "assert() is not implemented" -# define assert(expr) -#endif - -#endif /* __PJ_COMPAT_ASSERT_H__ */ - +/* $Header: /pjproject-0.3/pjlib/src/pj/compat/assert.h 3 9/22/05 10:31a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/compat/assert.h $ + * + * 3 9/22/05 10:31a Bennylp + * Moving all *.h files to include/. + * + * 2 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 1 9/17/05 10:36a Bennylp + * Created. + * + */ +#ifndef __PJ_COMPAT_ASSERT_H__ +#define __PJ_COMPAT_ASSERT_H__ + +/** + * @file assert.h + * @brief Provides assert() macro. + */ + +#if defined(PJ_HAS_ASSERT_H) && PJ_HAS_ASSERT_H != 0 +# include + +#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0 +# define assert(expr) do { \ + if (!(expr)) \ + printk("!!ASSERTION FAILED: [%s:%d] \"" #expr "\"\n",\ + __FILE__, __LINE__); \ + } while (0) + +#else +# warning "assert() is not implemented" +# define assert(expr) +#endif + +#endif /* __PJ_COMPAT_ASSERT_H__ */ + diff --git a/pjlib/include/pj/compat/cc_gcc.h b/pjlib/include/pj/compat/cc_gcc.h index dcae099d..83ae430f 100644 --- a/pjlib/include/pj/compat/cc_gcc.h +++ b/pjlib/include/pj/compat/cc_gcc.h @@ -1,32 +1,32 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/compat/cc_gcc.h 2 9/17/05 10:37a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/cc_gcc.h $ - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#ifndef __PJ_COMPAT_CC_GCC_H__ -#define __PJ_COMPAT_CC_GCC_H__ - -/** - * @file cc_gcc.h - * @brief Describes GCC compiler specifics. - */ - -#ifndef __GNUC__ -# error "This file is only for gcc!" -#endif - -#define PJ_INLINE_SPECIFIER static inline -#define PJ_THREAD_FUNC -#define PJ_NORETURN -#define PJ_ATTR_NORETURN __attribute__ ((noreturn)) - -#define PJ_HAS_INT64 1 - -typedef long long pj_int64_t; -typedef unsigned long long pj_uint64_t; - - -#endif /* __PJ_COMPAT_CC_GCC_H__ */ - +/* $Header: /pjproject-0.3/pjlib/src/pj/compat/cc_gcc.h 2 9/17/05 10:37a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/compat/cc_gcc.h $ + * + * 2 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#ifndef __PJ_COMPAT_CC_GCC_H__ +#define __PJ_COMPAT_CC_GCC_H__ + +/** + * @file cc_gcc.h + * @brief Describes GCC compiler specifics. + */ + +#ifndef __GNUC__ +# error "This file is only for gcc!" +#endif + +#define PJ_INLINE_SPECIFIER static inline +#define PJ_THREAD_FUNC +#define PJ_NORETURN +#define PJ_ATTR_NORETURN __attribute__ ((noreturn)) + +#define PJ_HAS_INT64 1 + +typedef long long pj_int64_t; +typedef unsigned long long pj_uint64_t; + + +#endif /* __PJ_COMPAT_CC_GCC_H__ */ + diff --git a/pjlib/include/pj/compat/cc_msvc.h b/pjlib/include/pj/compat/cc_msvc.h index 39f0acd9..f9271bae 100644 --- a/pjlib/include/pj/compat/cc_msvc.h +++ b/pjlib/include/pj/compat/cc_msvc.h @@ -1,40 +1,40 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/compat/cc_msvc.h 3 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/include/pj/compat/cc_msvc.h $ - * - * 3 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#ifndef __PJ_COMPAT_CC_MSVC_H__ -#define __PJ_COMPAT_CC_MSVC_H__ - -/** - * @file cc_msvc.h - * @brief Describes Microsoft Visual C compiler specifics. - */ - -#ifndef _MSC_VER -# error "This header file is only for Visual C compiler!" -#endif - -# pragma warning(disable: 4127) // conditional expression is constant -# pragma warning(disable: 4611) // not wise to mix setjmp with C++ -# pragma warning(disable: 4514) // unreferenced inline function has been removed -# ifdef __cplusplus -# define PJ_INLINE_SPECIFIER inline -# else -# define PJ_INLINE_SPECIFIER static __inline -# endif -# define PJ_THREAD_FUNC -# define PJ_NORETURN __declspec(noreturn) -# define PJ_ATTR_NORETURN - -# define PJ_HAS_INT64 1 -typedef __int64 pj_int64_t; -typedef unsigned __int64 pj_uint64_t; - -#endif /* __PJ_COMPAT_CC_MSVC_H__ */ +/* $Header: /pjproject-0.3/pjlib/include/pj/compat/cc_msvc.h 3 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/include/pj/compat/cc_msvc.h $ + * + * 3 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 2 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#ifndef __PJ_COMPAT_CC_MSVC_H__ +#define __PJ_COMPAT_CC_MSVC_H__ + +/** + * @file cc_msvc.h + * @brief Describes Microsoft Visual C compiler specifics. + */ + +#ifndef _MSC_VER +# error "This header file is only for Visual C compiler!" +#endif + +# pragma warning(disable: 4127) // conditional expression is constant +# pragma warning(disable: 4611) // not wise to mix setjmp with C++ +# pragma warning(disable: 4514) // unreferenced inline function has been removed +# ifdef __cplusplus +# define PJ_INLINE_SPECIFIER inline +# else +# define PJ_INLINE_SPECIFIER static __inline +# endif +# define PJ_THREAD_FUNC +# define PJ_NORETURN __declspec(noreturn) +# define PJ_ATTR_NORETURN + +# define PJ_HAS_INT64 1 +typedef __int64 pj_int64_t; +typedef unsigned __int64 pj_uint64_t; + +#endif /* __PJ_COMPAT_CC_MSVC_H__ */ diff --git a/pjlib/include/pj/compat/ctype.h b/pjlib/include/pj/compat/ctype.h index 18e8d475..7b53bf54 100644 --- a/pjlib/include/pj/compat/ctype.h +++ b/pjlib/include/pj/compat/ctype.h @@ -1,42 +1,42 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/compat/ctype.h 3 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/include/pj/compat/ctype.h $ - * - * 3 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 2 9/22/05 10:31a Bennylp - * Moving all *.h files to include/. - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_CTYPE_H__ -#define __PJ_COMPAT_CTYPE_H__ - -/** - * @file ctype.h - * @brief Provides ctype function family. - */ - -#if defined(PJ_HAS_CTYPE_H) && PJ_HAS_CTYPE_H != 0 -# include -#else -# define isalnum(c) (isalpha(c) || isdigit(c)) -# define isalpha(c) (islower(c) || isupper(c)) -# define isascii(c) (((unsigned char)(c))<=0x7f) -# define isdigit(c) ((c)>='0' && (c)<='9') -# define isspace(c) ((c)==' ' || (c)=='\t' ||\ - (c)=='\n' || (c)=='\r' || (c)=='\v') -# define islower(c) ((c)>='a' && (c)<='z') -# define isupper(c) ((c)>='A' && (c)<='Z') -# define isxdigit(c) (isdigit(c) || (tolower(c)>='a'&&tolower(c)<='f')) -# define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)+('a'-'A') : (c)) -# define toupper(c) (((c) >= 'a' && (c) <= 'z') ? (c)-('a'-'A') : (c)) -#endif - -#define isblank(c) (c==' ' || c=='\t') - - -#endif /* __PJ_COMPAT_CTYPE_H__ */ +/* $Header: /pjproject-0.3/pjlib/include/pj/compat/ctype.h 3 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/include/pj/compat/ctype.h $ + * + * 3 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 2 9/22/05 10:31a Bennylp + * Moving all *.h files to include/. + * + * 1 9/17/05 10:36a Bennylp + * Created. + * + */ +#ifndef __PJ_COMPAT_CTYPE_H__ +#define __PJ_COMPAT_CTYPE_H__ + +/** + * @file ctype.h + * @brief Provides ctype function family. + */ + +#if defined(PJ_HAS_CTYPE_H) && PJ_HAS_CTYPE_H != 0 +# include +#else +# define isalnum(c) (isalpha(c) || isdigit(c)) +# define isalpha(c) (islower(c) || isupper(c)) +# define isascii(c) (((unsigned char)(c))<=0x7f) +# define isdigit(c) ((c)>='0' && (c)<='9') +# define isspace(c) ((c)==' ' || (c)=='\t' ||\ + (c)=='\n' || (c)=='\r' || (c)=='\v') +# define islower(c) ((c)>='a' && (c)<='z') +# define isupper(c) ((c)>='A' && (c)<='Z') +# define isxdigit(c) (isdigit(c) || (tolower(c)>='a'&&tolower(c)<='f')) +# define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)+('a'-'A') : (c)) +# define toupper(c) (((c) >= 'a' && (c) <= 'z') ? (c)-('a'-'A') : (c)) +#endif + +#define isblank(c) (c==' ' || c=='\t') + + +#endif /* __PJ_COMPAT_CTYPE_H__ */ diff --git a/pjlib/include/pj/compat/errno.h b/pjlib/include/pj/compat/errno.h index a0ea2ea6..959f57fe 100644 --- a/pjlib/include/pj/compat/errno.h +++ b/pjlib/include/pj/compat/errno.h @@ -1,26 +1,27 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/compat/errno.h 2 10/14/05 12:26a Bennylp $ */ -#ifndef __PJ_COMPAT_ERRNO_H__ -#define __PJ_COMPAT_ERRNO_H__ - -#if defined(PJ_WIN32) && PJ_WIN32 != 0 - - typedef unsigned long pj_os_err_type; -# define pj_get_native_os_error() GetLastError() -# define pj_get_native_netos_error() WSAGetLastError() - -#elif (defined(PJ_LINUX) && PJ_LINUX != 0) || \ - (defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0) - - typedef int pj_os_err_type; -# define pj_get_native_os_error() (errno) -# define pj_get_native_netos_error() (errno) - -#else - -# error "Please define pj_os_err_type for this platform here!" - -#endif - - -#endif /* __PJ_COMPAT_ERRNO_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/compat/errno.h 2 10/14/05 12:26a Bennylp $ */ +#ifndef __PJ_COMPAT_ERRNO_H__ +#define __PJ_COMPAT_ERRNO_H__ + +#if defined(PJ_WIN32) && PJ_WIN32 != 0 + + typedef unsigned long pj_os_err_type; +# define pj_get_native_os_error() GetLastError() +# define pj_get_native_netos_error() WSAGetLastError() + +#elif (defined(PJ_LINUX) && PJ_LINUX != 0) || \ + (defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0) || \ + (defined(PJ_SUNOS) && PJ_SUNOS != 0) + + typedef int pj_os_err_type; +# define pj_get_native_os_error() (errno) +# define pj_get_native_netos_error() (errno) + +#else + +# error "Please define pj_os_err_type for this platform here!" + +#endif + + +#endif /* __PJ_COMPAT_ERRNO_H__ */ + diff --git a/pjlib/include/pj/compat/high_precision.h b/pjlib/include/pj/compat/high_precision.h index 2004fb2a..a29f5886 100644 --- a/pjlib/include/pj/compat/high_precision.h +++ b/pjlib/include/pj/compat/high_precision.h @@ -1,83 +1,85 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/compat/high_precision.h 3 10/29/05 11:51a Bennylp $ */ -#ifndef __PJ_COMPAT_HIGH_PRECISION_H__ -#define __PJ_COMPAT_HIGH_PRECISION_H__ - - -#if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT != 0 - /* - * The first choice for high precision math is to use double. - */ -# include - typedef double pj_highprec_t; - -# define PJ_HIGHPREC_VALUE_IS_ZERO(a) (a==0) -# define pj_highprec_mod(a,b) (a=fmod(a,b)) - -#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0 - -# include - - typedef pj_int64_t pj_highprec_t; - -# define pj_highprec_div(a1,a2) do_div(a1,a2) -# define pj_highprec_mod(a1,a2) (a1=do_mod(a1, a2)) - - PJ_INLINE(pj_int64_t) do_mod( pj_int64_t a1, pj_int64_t a2) - { - return do_div(a1,a2); - } - - -#elif defined(PJ_HAS_INT64) && PJ_HAS_INT64 != 0 - /* - * Next choice is to use 64-bit arithmatics. - */ - typedef pj_int64_t pj_highprec_t; - -#else - /* - * Last, fallback to 32-bit arithmetics. - */ - typedef pj_int32_t pj_highprec_t; - -#endif - -/** - * @def pj_highprec_mul - * pj_highprec_mul(a1, a2) - High Precision Multiplication - * Multiply a1 and a2, and store the result in a1. - */ -#ifndef pj_highprec_mul -# define pj_highprec_mul(a1,a2) (a1 = a1 * a2) -#endif - -/** - * @def pj_highprec_div - * pj_highprec_div(a1, a2) - High Precision Division - * Divide a2 from a1, and store the result in a1. - */ -#ifndef pj_highprec_div -# define pj_highprec_div(a1,a2) (a1 = a1 / a2) -#endif - -/** - * @def pj_highprec_mod - * pj_highprec_mod(a1, a2) - High Precision Modulus - * Get the modulus a2 from a1, and store the result in a1. - */ -#ifndef pj_highprec_mod -# define pj_highprec_mod(a1,a2) (a1 = a1 % a2) -#endif - - -/** - * @def PJ_HIGHPREC_VALUE_IS_ZERO(a) - * Test if the specified high precision value is zero. - */ -#ifndef PJ_HIGHPREC_VALUE_IS_ZERO -# define PJ_HIGHPREC_VALUE_IS_ZERO(a) (a==0) -#endif - - -#endif /* __PJ_COMPAT_HIGH_PRECISION_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/compat/high_precision.h 3 10/29/05 11:51a Bennylp $ */ +#ifndef __PJ_COMPAT_HIGH_PRECISION_H__ +#define __PJ_COMPAT_HIGH_PRECISION_H__ + + +#if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT != 0 + /* + * The first choice for high precision math is to use double. + */ +# include + typedef double pj_highprec_t; + +# define PJ_HIGHPREC_VALUE_IS_ZERO(a) (a==0) +# define pj_highprec_mod(a,b) (a=fmod(a,b)) + +#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0 + +# include + + typedef pj_int64_t pj_highprec_t; + +# define pj_highprec_div(a1,a2) do_div(a1,a2) +# define pj_highprec_mod(a1,a2) (a1=do_mod(a1, a2)) + + PJ_INLINE(pj_int64_t) do_mod( pj_int64_t a1, pj_int64_t a2) + { + return do_div(a1,a2); + } + + +#elif defined(PJ_HAS_INT64) && PJ_HAS_INT64 != 0 + /* + * Next choice is to use 64-bit arithmatics. + */ + typedef pj_int64_t pj_highprec_t; + +#else +# warning "High precision math is not available" + + /* + * Last, fallback to 32-bit arithmetics. + */ + typedef pj_int32_t pj_highprec_t; + +#endif + +/** + * @def pj_highprec_mul + * pj_highprec_mul(a1, a2) - High Precision Multiplication + * Multiply a1 and a2, and store the result in a1. + */ +#ifndef pj_highprec_mul +# define pj_highprec_mul(a1,a2) (a1 = a1 * a2) +#endif + +/** + * @def pj_highprec_div + * pj_highprec_div(a1, a2) - High Precision Division + * Divide a2 from a1, and store the result in a1. + */ +#ifndef pj_highprec_div +# define pj_highprec_div(a1,a2) (a1 = a1 / a2) +#endif + +/** + * @def pj_highprec_mod + * pj_highprec_mod(a1, a2) - High Precision Modulus + * Get the modulus a2 from a1, and store the result in a1. + */ +#ifndef pj_highprec_mod +# define pj_highprec_mod(a1,a2) (a1 = a1 % a2) +#endif + + +/** + * @def PJ_HIGHPREC_VALUE_IS_ZERO(a) + * Test if the specified high precision value is zero. + */ +#ifndef PJ_HIGHPREC_VALUE_IS_ZERO +# define PJ_HIGHPREC_VALUE_IS_ZERO(a) (a==0) +#endif + + +#endif /* __PJ_COMPAT_HIGH_PRECISION_H__ */ + diff --git a/pjlib/include/pj/compat/m_alpha.h b/pjlib/include/pj/compat/m_alpha.h index a112e0c2..02681b82 100644 --- a/pjlib/include/pj/compat/m_alpha.h +++ b/pjlib/include/pj/compat/m_alpha.h @@ -1,23 +1,23 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/compat/m_alpha.h 1 10/29/05 5:23p Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/include/pj/compat/m_alpha.h $ - * - * 1 10/29/05 5:23p Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_M_ALPHA_H__ -#define __PJ_COMPAT_M_ALPHA_H__ - -/** - * @file m_alpha.h - * @brief Describes Alpha processor family specifics. - */ - -#define PJ_HAS_PENTIUM 0 -#define PJ_IS_LITTLE_ENDIAN 1 -#define PJ_IS_BIG_ENDIAN 0 - - -#endif /* __PJ_COMPAT_M_ALPHA_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/compat/m_alpha.h 1 10/29/05 5:23p Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/include/pj/compat/m_alpha.h $ + * + * 1 10/29/05 5:23p Bennylp + * Created. + * + */ +#ifndef __PJ_COMPAT_M_ALPHA_H__ +#define __PJ_COMPAT_M_ALPHA_H__ + +/** + * @file m_alpha.h + * @brief Describes Alpha processor family specifics. + */ + +#define PJ_HAS_PENTIUM 0 +#define PJ_IS_LITTLE_ENDIAN 1 +#define PJ_IS_BIG_ENDIAN 0 + + +#endif /* __PJ_COMPAT_M_ALPHA_H__ */ + diff --git a/pjlib/include/pj/compat/m_i386.h b/pjlib/include/pj/compat/m_i386.h index 2c9ef262..b291aee2 100644 --- a/pjlib/include/pj/compat/m_i386.h +++ b/pjlib/include/pj/compat/m_i386.h @@ -1,26 +1,26 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/compat/m_i386.h 3 9/21/05 1:39p Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/m_i386.h $ - * - * 3 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#ifndef __PJ_COMPAT_M_i386_H__ -#define __PJ_COMPAT_M_i386_H__ - -/** - * @file m_i386.h - * @brief Describes Intel i386 family processor specifics. - */ - -#define PJ_M_I386 1 - -#define PJ_HAS_PENTIUM 1 -#define PJ_IS_LITTLE_ENDIAN 1 -#define PJ_IS_BIG_ENDIAN 0 - - -#endif /* __PJ_COMPAT_M_i386_H__ */ +/* $Header: /pjproject-0.3/pjlib/src/pj/compat/m_i386.h 3 9/21/05 1:39p Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/compat/m_i386.h $ + * + * 3 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 2 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#ifndef __PJ_COMPAT_M_i386_H__ +#define __PJ_COMPAT_M_i386_H__ + +/** + * @file m_i386.h + * @brief Describes Intel i386 family processor specifics. + */ + +#define PJ_M_I386 1 + +#define PJ_HAS_PENTIUM 1 +#define PJ_IS_LITTLE_ENDIAN 1 +#define PJ_IS_BIG_ENDIAN 0 + + +#endif /* __PJ_COMPAT_M_i386_H__ */ diff --git a/pjlib/include/pj/compat/m_m68k.h b/pjlib/include/pj/compat/m_m68k.h index 5cdcde53..bb126d16 100644 --- a/pjlib/include/pj/compat/m_m68k.h +++ b/pjlib/include/pj/compat/m_m68k.h @@ -1,21 +1,21 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/compat/m_m68k.h 2 9/17/05 10:37a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/m_m68k.h $ - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#ifndef __PJ_COMPAT_M_M68K_H__ -#define __PJ_COMPAT_M_M68K_H__ - -/** - * @file m_m68k.h - * @brief Describes Motorola m68k family processor specifics. - */ - -#define PJ_HAS_PENTIUM 0 -#define PJ_IS_LITTLE_ENDIAN 1 -#define PJ_IS_BIG_ENDIAN 0 - - -#endif /* __PJ_COMPAT_M_M68K_H__ */ +/* $Header: /pjproject-0.3/pjlib/src/pj/compat/m_m68k.h 2 9/17/05 10:37a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/compat/m_m68k.h $ + * + * 2 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#ifndef __PJ_COMPAT_M_M68K_H__ +#define __PJ_COMPAT_M_M68K_H__ + +/** + * @file m_m68k.h + * @brief Describes Motorola m68k family processor specifics. + */ + +#define PJ_HAS_PENTIUM 0 +#define PJ_IS_LITTLE_ENDIAN 1 +#define PJ_IS_BIG_ENDIAN 0 + + +#endif /* __PJ_COMPAT_M_M68K_H__ */ diff --git a/pjlib/include/pj/compat/m_sparc.h b/pjlib/include/pj/compat/m_sparc.h new file mode 100644 index 00000000..f0b55732 --- /dev/null +++ b/pjlib/include/pj/compat/m_sparc.h @@ -0,0 +1,21 @@ +/* $Header: $ */ +/* + *$Log: $ + * + */ +#ifndef __PJ_COMPAT_M_SPARC_H__ +#define __PJ_COMPAT_M_SPARC_H__ + +/** + * @file m_sparc.h + * @brief Describes SPARC family processor specifics. + */ + +#define PJ_SPARC 1 + +#define PJ_HAS_PENTIUM 0 +#define PJ_IS_LITTLE_ENDIAN 0 +#define PJ_IS_BIG_ENDIAN 1 + + +#endif /* __PJ_COMPAT_M_SPARC_H__ */ diff --git a/pjlib/include/pj/compat/malloc.h b/pjlib/include/pj/compat/malloc.h index b5a81265..225713c2 100644 --- a/pjlib/include/pj/compat/malloc.h +++ b/pjlib/include/pj/compat/malloc.h @@ -1,25 +1,25 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/compat/malloc.h 2 9/17/05 10:37a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/malloc.h $ - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - * 1 9/16/05 10:02p Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_MALLOC_H__ -#define __PJ_COMPAT_MALLOC_H__ - -/** - * @file malloc.h - * @brief Provides malloc() and free() functions. - */ - -#if defined(PJ_HAS_MALLOC_H) && PJ_HAS_MALLOC_H != 0 -# include -#elif defined(PJ_HAS_STDLIB_H) && PJ_HAS_STDLIB_H != 0 -# include -#endif - -#endif /* __PJ_COMPAT_MALLOC_H__ */ +/* $Header: /pjproject-0.3/pjlib/src/pj/compat/malloc.h 2 9/17/05 10:37a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/compat/malloc.h $ + * + * 2 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + * 1 9/16/05 10:02p Bennylp + * Created. + * + */ +#ifndef __PJ_COMPAT_MALLOC_H__ +#define __PJ_COMPAT_MALLOC_H__ + +/** + * @file malloc.h + * @brief Provides malloc() and free() functions. + */ + +#if defined(PJ_HAS_MALLOC_H) && PJ_HAS_MALLOC_H != 0 +# include +#elif defined(PJ_HAS_STDLIB_H) && PJ_HAS_STDLIB_H != 0 +# include +#endif + +#endif /* __PJ_COMPAT_MALLOC_H__ */ diff --git a/pjlib/include/pj/compat/os_linux.h b/pjlib/include/pj/compat/os_linux.h index 2f5e65af..2779f58f 100644 --- a/pjlib/include/pj/compat/os_linux.h +++ b/pjlib/include/pj/compat/os_linux.h @@ -1,69 +1,69 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/compat/os_linux.h 6 10/29/05 11:51a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/include/pj/compat/os_linux.h $ - * - * 6 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 5 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 4 9/22/05 10:31a Bennylp - * Moving all *.h files to include/. - * - * 3 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#ifndef __PJ_COMPAT_OS_LINUX_H__ -#define __PJ_COMPAT_OS_LINUX_H__ - -/** - * @file os_linux.h - * @brief Describes Linux operating system specifics. - */ - -#define PJ_HAS_ARPA_INET_H 1 -#define PJ_HAS_ASSERT_H 1 -#define PJ_HAS_CTYPE_H 1 -#define PJ_HAS_ERRNO_H 1 -#define PJ_HAS_LINUX_SOCKET_H 0 -#define PJ_HAS_MALLOC_H 1 -#define PJ_HAS_NETDB_H 1 -#define PJ_HAS_NETINET_IN_H 1 -#define PJ_HAS_SETJMP_H 1 -#define PJ_HAS_STDARG_H 1 -#define PJ_HAS_STDDEF_H 1 -#define PJ_HAS_STDIO_H 1 -#define PJ_HAS_STDLIB_H 1 -#define PJ_HAS_STRING_H 1 -#define PJ_HAS_SYS_IOCTL_H 1 -#define PJ_HAS_SYS_SELECT_H 1 -#define PJ_HAS_SYS_SOCKET_H 1 -#define PJ_HAS_SYS_TIMEB_H 1 -#define PJ_HAS_SYS_TYPES_H 1 -#define PJ_HAS_TIME_H 1 -#define PJ_HAS_UNISTD_H 1 - -#define PJ_HAS_MSWSOCK_H 0 -#define PJ_HAS_WINSOCK_H 0 -#define PJ_HAS_WINSOCK2_H 0 - -#define PJ_SOCK_HAS_INET_ATON 1 - -/* Default threading is enabled, unless it's overridden. */ -#ifndef PJ_HAS_THREADS -# define PJ_HAS_THREADS (1) -#endif - -#define PJ_HAS_HIGH_RES_TIMER 1 -#define PJ_HAS_MALLOC 1 -#define PJ_OS_HAS_CHECK_STACK 0 - -#define PJ_ATOMIC_VALUE_TYPE long - -#endif /* __PJ_COMPAT_OS_LINUX_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/compat/os_linux.h 6 10/29/05 11:51a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/include/pj/compat/os_linux.h $ + * + * 6 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 5 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 4 9/22/05 10:31a Bennylp + * Moving all *.h files to include/. + * + * 3 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 2 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#ifndef __PJ_COMPAT_OS_LINUX_H__ +#define __PJ_COMPAT_OS_LINUX_H__ + +/** + * @file os_linux.h + * @brief Describes Linux operating system specifics. + */ + +#define PJ_HAS_ARPA_INET_H 1 +#define PJ_HAS_ASSERT_H 1 +#define PJ_HAS_CTYPE_H 1 +#define PJ_HAS_ERRNO_H 1 +#define PJ_HAS_LINUX_SOCKET_H 0 +#define PJ_HAS_MALLOC_H 1 +#define PJ_HAS_NETDB_H 1 +#define PJ_HAS_NETINET_IN_H 1 +#define PJ_HAS_SETJMP_H 1 +#define PJ_HAS_STDARG_H 1 +#define PJ_HAS_STDDEF_H 1 +#define PJ_HAS_STDIO_H 1 +#define PJ_HAS_STDLIB_H 1 +#define PJ_HAS_STRING_H 1 +#define PJ_HAS_SYS_IOCTL_H 1 +#define PJ_HAS_SYS_SELECT_H 1 +#define PJ_HAS_SYS_SOCKET_H 1 +#define PJ_HAS_SYS_TIMEB_H 1 +#define PJ_HAS_SYS_TYPES_H 1 +#define PJ_HAS_TIME_H 1 +#define PJ_HAS_UNISTD_H 1 + +#define PJ_HAS_MSWSOCK_H 0 +#define PJ_HAS_WINSOCK_H 0 +#define PJ_HAS_WINSOCK2_H 0 + +#define PJ_SOCK_HAS_INET_ATON 1 + +/* Default threading is enabled, unless it's overridden. */ +#ifndef PJ_HAS_THREADS +# define PJ_HAS_THREADS (1) +#endif + +#define PJ_HAS_HIGH_RES_TIMER 1 +#define PJ_HAS_MALLOC 1 +#define PJ_OS_HAS_CHECK_STACK 0 + +#define PJ_ATOMIC_VALUE_TYPE long + +#endif /* __PJ_COMPAT_OS_LINUX_H__ */ + diff --git a/pjlib/include/pj/compat/os_linux_kernel.h b/pjlib/include/pj/compat/os_linux_kernel.h index 2ebbb322..e2cec344 100644 --- a/pjlib/include/pj/compat/os_linux_kernel.h +++ b/pjlib/include/pj/compat/os_linux_kernel.h @@ -1,86 +1,86 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/compat/os_linux_kernel.h 4 10/29/05 11:51a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/include/pj/compat/os_linux_kernel.h $ - * - * 4 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 3 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 2 9/22/05 10:31a Bennylp - * Moving all *.h files to include/. - * - * 1 9/21/05 1:38p Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_OS_LINUX_KERNEL_H__ -#define __PJ_COMPAT_OS_LINUX_KERNEL_H__ - -/** - * @file os_linux.h - * @brief Describes Linux operating system specifics. - */ - -#define PJ_HAS_ARPA_INET_H 0 -#define PJ_HAS_ASSERT_H 0 -#define PJ_HAS_CTYPE_H 0 -#define PJ_HAS_ERRNO_H 0 -#define PJ_HAS_LINUX_SOCKET_H 1 -#define PJ_HAS_MALLOC_H 0 -#define PJ_HAS_NETDB_H 0 -#define PJ_HAS_NETINET_IN_H 0 -#define PJ_HAS_SETJMP_H 0 -#define PJ_HAS_STDARG_H 1 -#define PJ_HAS_STDDEF_H 0 -#define PJ_HAS_STDIO_H 0 -#define PJ_HAS_STDLIB_H 0 -#define PJ_HAS_STRING_H 0 -#define PJ_HAS_SYS_IOCTL_H 0 -#define PJ_HAS_SYS_SELECT_H 0 -#define PJ_HAS_SYS_SOCKET_H 0 -#define PJ_HAS_SYS_TIMEB_H 0 -#define PJ_HAS_SYS_TYPES_H 0 -#define PJ_HAS_TIME_H 0 -#define PJ_HAS_UNISTD_H 0 - -#define PJ_HAS_MSWSOCK_H 0 -#define PJ_HAS_WINSOCK_H 0 -#define PJ_HAS_WINSOCK2_H 0 - -#define PJ_SOCK_HAS_INET_ATON 0 - -#ifndef PJ_HAS_THREADS -# define PJ_HAS_THREADS (1) -#endif - - -/* - * Declare __FD_SETSIZE now before including . - */ -#define __FD_SETSIZE PJ_IOQUEUE_MAX_HANDLES - -#define NULL ((void*)0) - -#include /* Needed by all modules */ -#include /* Needed for KERN_INFO */ - -#define __PJ_EXPORT_SYMBOL(a) EXPORT_SYMBOL(a); - -/* - * Override features. - */ -#define PJ_HAS_FLOATING_POINT 0 -#define PJ_HAS_MALLOC 0 -#define PJ_HAS_SEMAPHORE 0 -#define PJ_HAS_EVENT_OBJ 0 -#define PJ_HAS_HIGH_RES_TIMER 1 -#define PJ_OS_HAS_CHECK_STACK 0 -#define PJ_TERM_HAS_COLOR 0 - -#define PJ_ATOMIC_VALUE_TYPE int -#define PJ_THREAD_DESC_SIZE 128 - -#endif /* __PJ_COMPAT_OS_LINUX_KERNEL_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/compat/os_linux_kernel.h 4 10/29/05 11:51a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/include/pj/compat/os_linux_kernel.h $ + * + * 4 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 3 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 2 9/22/05 10:31a Bennylp + * Moving all *.h files to include/. + * + * 1 9/21/05 1:38p Bennylp + * Created. + * + */ +#ifndef __PJ_COMPAT_OS_LINUX_KERNEL_H__ +#define __PJ_COMPAT_OS_LINUX_KERNEL_H__ + +/** + * @file os_linux.h + * @brief Describes Linux operating system specifics. + */ + +#define PJ_HAS_ARPA_INET_H 0 +#define PJ_HAS_ASSERT_H 0 +#define PJ_HAS_CTYPE_H 0 +#define PJ_HAS_ERRNO_H 0 +#define PJ_HAS_LINUX_SOCKET_H 1 +#define PJ_HAS_MALLOC_H 0 +#define PJ_HAS_NETDB_H 0 +#define PJ_HAS_NETINET_IN_H 0 +#define PJ_HAS_SETJMP_H 0 +#define PJ_HAS_STDARG_H 1 +#define PJ_HAS_STDDEF_H 0 +#define PJ_HAS_STDIO_H 0 +#define PJ_HAS_STDLIB_H 0 +#define PJ_HAS_STRING_H 0 +#define PJ_HAS_SYS_IOCTL_H 0 +#define PJ_HAS_SYS_SELECT_H 0 +#define PJ_HAS_SYS_SOCKET_H 0 +#define PJ_HAS_SYS_TIMEB_H 0 +#define PJ_HAS_SYS_TYPES_H 0 +#define PJ_HAS_TIME_H 0 +#define PJ_HAS_UNISTD_H 0 + +#define PJ_HAS_MSWSOCK_H 0 +#define PJ_HAS_WINSOCK_H 0 +#define PJ_HAS_WINSOCK2_H 0 + +#define PJ_SOCK_HAS_INET_ATON 0 + +#ifndef PJ_HAS_THREADS +# define PJ_HAS_THREADS (1) +#endif + + +/* + * Declare __FD_SETSIZE now before including . + */ +#define __FD_SETSIZE PJ_IOQUEUE_MAX_HANDLES + +#define NULL ((void*)0) + +#include /* Needed by all modules */ +#include /* Needed for KERN_INFO */ + +#define __PJ_EXPORT_SYMBOL(a) EXPORT_SYMBOL(a); + +/* + * Override features. + */ +#define PJ_HAS_FLOATING_POINT 0 +#define PJ_HAS_MALLOC 0 +#define PJ_HAS_SEMAPHORE 0 +#define PJ_HAS_EVENT_OBJ 0 +#define PJ_HAS_HIGH_RES_TIMER 1 +#define PJ_OS_HAS_CHECK_STACK 0 +#define PJ_TERM_HAS_COLOR 0 + +#define PJ_ATOMIC_VALUE_TYPE int +#define PJ_THREAD_DESC_SIZE 128 + +#endif /* __PJ_COMPAT_OS_LINUX_KERNEL_H__ */ + diff --git a/pjlib/include/pj/compat/os_palmos.h b/pjlib/include/pj/compat/os_palmos.h index 1242bec1..109b020a 100644 --- a/pjlib/include/pj/compat/os_palmos.h +++ b/pjlib/include/pj/compat/os_palmos.h @@ -1,54 +1,54 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/compat/os_palmos.h 3 9/21/05 1:39p Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/os_palmos.h $ - * - * 3 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#ifndef __PJ_COMPAT_OS_PALMOS_H__ -#define __PJ_COMPAT_OS_PALMOS_H__ - -/** - * @file os_palmos.h - * @brief Describes PalmOS operating system specifics. - */ - -#define PJ_HAS_ARPA_INET_H 0 -#define PJ_HAS_ASSERT_H 1 -#define PJ_HAS_CTYPE_H 1 -#define PJ_HAS_ERRNO_H 0 -#define PJ_HAS_MALLOC_H 1 -#define PJ_HAS_NETDB_H 0 -#define PJ_HAS_NETINET_IN_H 0 -#define PJ_HAS_SETJMP_H 1 -#define PJ_HAS_STDARG_H 1 -#define PJ_HAS_STDDEF_H 1 -#define PJ_HAS_STDIO_H 1 -#define PJ_HAS_STDLIB_H 1 -#define PJ_HAS_STRING_H 1 -#define PJ_HAS_SYS_IOCTL_H 0 -#define PJ_HAS_SYS_SELECT_H 0 -#define PJ_HAS_SYS_SOCKET_H 0 -#define PJ_HAS_SYS_TIMEB_H 0 -#define PJ_HAS_SYS_TYPES_H 1 -#define PJ_HAS_TIME_H 1 -#define PJ_HAS_UNISTD_H 0 - -#define PJ_HAS_MSWSOCK_H 0 -#define PJ_HAS_WINSOCK_H 0 -#define PJ_HAS_WINSOCK2_H 0 - -#define PJ_SOCK_HAS_INET_ATON 0 - -/* Default threading is enabled, unless it's overridden. */ -#ifndef PJ_HAS_THREADS -# define PJ_HAS_THREADS (1) -#endif - -#define PJ_HAS_HIGH_RES_TIMER 1 -#define PJ_OS_HAS_CHECK_STACK 0 - -#endif /* __PJ_COMPAT_OS_PALMOS_H__ */ +/* $Header: /pjproject-0.3/pjlib/src/pj/compat/os_palmos.h 3 9/21/05 1:39p Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/compat/os_palmos.h $ + * + * 3 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 2 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#ifndef __PJ_COMPAT_OS_PALMOS_H__ +#define __PJ_COMPAT_OS_PALMOS_H__ + +/** + * @file os_palmos.h + * @brief Describes PalmOS operating system specifics. + */ + +#define PJ_HAS_ARPA_INET_H 0 +#define PJ_HAS_ASSERT_H 1 +#define PJ_HAS_CTYPE_H 1 +#define PJ_HAS_ERRNO_H 0 +#define PJ_HAS_MALLOC_H 1 +#define PJ_HAS_NETDB_H 0 +#define PJ_HAS_NETINET_IN_H 0 +#define PJ_HAS_SETJMP_H 1 +#define PJ_HAS_STDARG_H 1 +#define PJ_HAS_STDDEF_H 1 +#define PJ_HAS_STDIO_H 1 +#define PJ_HAS_STDLIB_H 1 +#define PJ_HAS_STRING_H 1 +#define PJ_HAS_SYS_IOCTL_H 0 +#define PJ_HAS_SYS_SELECT_H 0 +#define PJ_HAS_SYS_SOCKET_H 0 +#define PJ_HAS_SYS_TIMEB_H 0 +#define PJ_HAS_SYS_TYPES_H 1 +#define PJ_HAS_TIME_H 1 +#define PJ_HAS_UNISTD_H 0 + +#define PJ_HAS_MSWSOCK_H 0 +#define PJ_HAS_WINSOCK_H 0 +#define PJ_HAS_WINSOCK2_H 0 + +#define PJ_SOCK_HAS_INET_ATON 0 + +/* Default threading is enabled, unless it's overridden. */ +#ifndef PJ_HAS_THREADS +# define PJ_HAS_THREADS (1) +#endif + +#define PJ_HAS_HIGH_RES_TIMER 1 +#define PJ_OS_HAS_CHECK_STACK 0 + +#endif /* __PJ_COMPAT_OS_PALMOS_H__ */ diff --git a/pjlib/include/pj/compat/os_sunos.h b/pjlib/include/pj/compat/os_sunos.h new file mode 100644 index 00000000..1704ceda --- /dev/null +++ b/pjlib/include/pj/compat/os_sunos.h @@ -0,0 +1,56 @@ +/* $Header: $ */ +/* $Log: $ + * + */ +#ifndef __PJ_COMPAT_OS_SUNOS_H__ +#define __PJ_COMPAT_OS_SUNOS_H__ + +/** + * @file os_sunos.h + * @brief Describes SunOS/Solaris operating system specifics. + */ + +#define PJ_HAS_ARPA_INET_H 1 +#define PJ_HAS_ASSERT_H 1 +#define PJ_HAS_CTYPE_H 1 +#define PJ_HAS_ERRNO_H 1 +#define PJ_HAS_LINUX_SOCKET_H 0 +#define PJ_HAS_MALLOC_H 1 +#define PJ_HAS_NETDB_H 1 +#define PJ_HAS_NETINET_IN_H 1 +#define PJ_HAS_SETJMP_H 1 +#define PJ_HAS_STDARG_H 1 +#define PJ_HAS_STDDEF_H 1 +#define PJ_HAS_STDIO_H 1 +#define PJ_HAS_STDLIB_H 1 +#define PJ_HAS_STRING_H 1 +#define PJ_HAS_SYS_IOCTL_H 1 +#define PJ_HAS_SYS_SELECT_H 1 +#define PJ_HAS_SYS_SOCKET_H 1 +#define PJ_HAS_SYS_TIMEB_H 1 +#define PJ_HAS_SYS_TYPES_H 1 +#define PJ_HAS_TIME_H 1 +#define PJ_HAS_UNISTD_H 1 + +#define PJ_HAS_MSWSOCK_H 0 +#define PJ_HAS_WINSOCK_H 0 +#define PJ_HAS_WINSOCK2_H 0 + +#define PJ_SOCK_HAS_INET_ATON 0 + +/* Default threading is enabled, unless it's overridden. */ +#ifndef PJ_HAS_THREADS +# define PJ_HAS_THREADS (1) +#endif + +#define PJ_HAS_HIGH_RES_TIMER 1 +#define PJ_HAS_MALLOC 1 +#define PJ_OS_HAS_CHECK_STACK 0 + +#define PJ_ATOMIC_VALUE_TYPE long + +/* Get BSD related identifers in Sun's include files */ +#define BSD_COMP + +#endif /* __PJ_COMPAT_OS_SUNOS_H__ */ + diff --git a/pjlib/include/pj/compat/os_win32.h b/pjlib/include/pj/compat/os_win32.h index d7a92c9b..13a4a690 100644 --- a/pjlib/include/pj/compat/os_win32.h +++ b/pjlib/include/pj/compat/os_win32.h @@ -1,72 +1,72 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/compat/os_win32.h 6 10/29/05 11:51a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/include/pj/compat/os_win32.h $ - * - * 6 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 5 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 4 9/22/05 10:31a Bennylp - * Moving all *.h files to include/. - * - * 3 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#ifndef __PJ_COMPAT_OS_WIN32_H__ -#define __PJ_COMPAT_OS_WIN32_H__ - -/** - * @file os_win32.h - * @brief Describes Win32 operating system family specifics. - */ - -#define WIN32_LEAN_AND_MEAN -#define PJ_WIN32_WINNT 0x0400 -#define _WIN32_WINNT PJ_WIN32_WINNT - -#define PJ_HAS_ARPA_INET_H 0 -#define PJ_HAS_ASSERT_H 1 -#define PJ_HAS_CTYPE_H 1 -#define PJ_HAS_ERRNO_H 0 /* Must be zero, otherwise errno_test() fails. */ -#define PJ_HAS_LINUX_SOCKET_H 0 -#define PJ_HAS_MALLOC_H 1 -#define PJ_HAS_NETDB_H 0 -#define PJ_HAS_NETINET_IN_H 0 -#define PJ_HAS_SETJMP_H 1 -#define PJ_HAS_STDARG_H 1 -#define PJ_HAS_STDDEF_H 1 -#define PJ_HAS_STDIO_H 1 -#define PJ_HAS_STDLIB_H 1 -#define PJ_HAS_STRING_H 1 -#define PJ_HAS_SYS_IOCTL_H 0 -#define PJ_HAS_SYS_SELECT_H 0 -#define PJ_HAS_SYS_SOCKET_H 0 -#define PJ_HAS_SYS_TIMEB_H 1 -#define PJ_HAS_SYS_TYPES_H 1 -#define PJ_HAS_TIME_H 1 -#define PJ_HAS_UNISTD_H 0 - -#define PJ_HAS_MSWSOCK_H 1 -#define PJ_HAS_WINSOCK_H 0 -#define PJ_HAS_WINSOCK2_H 1 - -#define PJ_SOCK_HAS_INET_ATON 0 - -/* Default threading is enabled, unless it's overridden. */ -#ifndef PJ_HAS_THREADS -# define PJ_HAS_THREADS (1) -#endif - -#define PJ_HAS_HIGH_RES_TIMER 1 -#define PJ_HAS_MALLOC 1 -#define PJ_OS_HAS_CHECK_STACK 1 - -#define PJ_ATOMIC_VALUE_TYPE long - -#endif /* __PJ_COMPAT_OS_WIN32_H__ */ +/* $Header: /pjproject-0.3/pjlib/include/pj/compat/os_win32.h 6 10/29/05 11:51a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/include/pj/compat/os_win32.h $ + * + * 6 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 5 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 4 9/22/05 10:31a Bennylp + * Moving all *.h files to include/. + * + * 3 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 2 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#ifndef __PJ_COMPAT_OS_WIN32_H__ +#define __PJ_COMPAT_OS_WIN32_H__ + +/** + * @file os_win32.h + * @brief Describes Win32 operating system family specifics. + */ + +#define WIN32_LEAN_AND_MEAN +#define PJ_WIN32_WINNT 0x0400 +#define _WIN32_WINNT PJ_WIN32_WINNT + +#define PJ_HAS_ARPA_INET_H 0 +#define PJ_HAS_ASSERT_H 1 +#define PJ_HAS_CTYPE_H 1 +#define PJ_HAS_ERRNO_H 0 /* Must be zero, otherwise errno_test() fails. */ +#define PJ_HAS_LINUX_SOCKET_H 0 +#define PJ_HAS_MALLOC_H 1 +#define PJ_HAS_NETDB_H 0 +#define PJ_HAS_NETINET_IN_H 0 +#define PJ_HAS_SETJMP_H 1 +#define PJ_HAS_STDARG_H 1 +#define PJ_HAS_STDDEF_H 1 +#define PJ_HAS_STDIO_H 1 +#define PJ_HAS_STDLIB_H 1 +#define PJ_HAS_STRING_H 1 +#define PJ_HAS_SYS_IOCTL_H 0 +#define PJ_HAS_SYS_SELECT_H 0 +#define PJ_HAS_SYS_SOCKET_H 0 +#define PJ_HAS_SYS_TIMEB_H 1 +#define PJ_HAS_SYS_TYPES_H 1 +#define PJ_HAS_TIME_H 1 +#define PJ_HAS_UNISTD_H 0 + +#define PJ_HAS_MSWSOCK_H 1 +#define PJ_HAS_WINSOCK_H 0 +#define PJ_HAS_WINSOCK2_H 1 + +#define PJ_SOCK_HAS_INET_ATON 0 + +/* Default threading is enabled, unless it's overridden. */ +#ifndef PJ_HAS_THREADS +# define PJ_HAS_THREADS (1) +#endif + +#define PJ_HAS_HIGH_RES_TIMER 1 +#define PJ_HAS_MALLOC 1 +#define PJ_OS_HAS_CHECK_STACK 1 + +#define PJ_ATOMIC_VALUE_TYPE long + +#endif /* __PJ_COMPAT_OS_WIN32_H__ */ diff --git a/pjlib/include/pj/compat/rand.h b/pjlib/include/pj/compat/rand.h index 31461b37..60c2be59 100644 --- a/pjlib/include/pj/compat/rand.h +++ b/pjlib/include/pj/compat/rand.h @@ -1,65 +1,65 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/compat/rand.h 3 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/include/pj/compat/rand.h $ - * - * 3 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 2 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_RAND_H__ -#define __PJ_COMPAT_RAND_H__ - -/** - * @file rand.h - * @brief Provides platform_rand() and platform_srand() functions. - */ - -#if defined(PJ_HAS_STDLIB_H) && PJ_HAS_STDLIB_H != 0 - /* - * Use stdlib based rand() and srand(). - */ -# include -# define platform_srand srand -# if defined(RAND_MAX) && RAND_MAX <= 0xFFFF - /* - * When rand() is only 16 bit strong, double the strength - * by calling it twice! - */ - PJ_INLINE(int) platform_rand(void) - { - return ((rand() & 0xFFFF) << 16) | (rand() & 0xFFFF); - } -# else -# define platform_rand rand -# endif - -#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0 - /* - * Linux kernel mode random number generator. - */ -# include -# define platform_srand(seed) - - PJ_INLINE(int) platform_rand(void) - { - int value; - get_random_bytes((void*)&value, sizeof(value)); - return value; - } - -#else -# warning "platform_rand() is not implemented" -# define platform_rand() 1 -# define platform_srand(seed) - -#endif - - -#endif /* __PJ_COMPAT_RAND_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/compat/rand.h 3 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/include/pj/compat/rand.h $ + * + * 3 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 2 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 1 9/17/05 10:36a Bennylp + * Created. + * + */ +#ifndef __PJ_COMPAT_RAND_H__ +#define __PJ_COMPAT_RAND_H__ + +/** + * @file rand.h + * @brief Provides platform_rand() and platform_srand() functions. + */ + +#if defined(PJ_HAS_STDLIB_H) && PJ_HAS_STDLIB_H != 0 + /* + * Use stdlib based rand() and srand(). + */ +# include +# define platform_srand srand +# if defined(RAND_MAX) && RAND_MAX <= 0xFFFF + /* + * When rand() is only 16 bit strong, double the strength + * by calling it twice! + */ + PJ_INLINE(int) platform_rand(void) + { + return ((rand() & 0xFFFF) << 16) | (rand() & 0xFFFF); + } +# else +# define platform_rand rand +# endif + +#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0 + /* + * Linux kernel mode random number generator. + */ +# include +# define platform_srand(seed) + + PJ_INLINE(int) platform_rand(void) + { + int value; + get_random_bytes((void*)&value, sizeof(value)); + return value; + } + +#else +# warning "platform_rand() is not implemented" +# define platform_rand() 1 +# define platform_srand(seed) + +#endif + + +#endif /* __PJ_COMPAT_RAND_H__ */ + diff --git a/pjlib/include/pj/compat/setjmp.h b/pjlib/include/pj/compat/setjmp.h index 2bbd0cd4..1ffd9eab 100644 --- a/pjlib/include/pj/compat/setjmp.h +++ b/pjlib/include/pj/compat/setjmp.h @@ -1,89 +1,89 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/compat/setjmp.h 4 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/include/pj/compat/setjmp.h $ - * - * 4 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 3 9/22/05 10:31a Bennylp - * Moving all *.h files to include/. - * - * 2 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_SETJMP_H__ -#define __PJ_COMPAT_SETJMP_H__ - -/** - * @file setjmp.h - * @brief Provides setjmp.h functionality. - */ - -#if defined(PJ_HAS_SETJMP_H) && PJ_HAS_SETJMP_H != 0 -# include - typedef jmp_buf pj_jmp_buf; -# define pj_setjmp(buf) setjmp(buf) -# define pj_longjmp(buf,d) longjmp(buf,d) - -#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0 && \ - defined(PJ_M_I386) && PJ_M_I386 != 0 - - /* - * These are taken from uClibc. - * Copyright (C) 2000-2003 Erik Andersen - */ -# if defined __USE_MISC || defined _ASM -# define JB_BX 0 -# define JB_SI 1 -# define JB_DI 2 -# define JB_BP 3 -# define JB_SP 4 -# define JB_PC 5 -# define JB_SIZE 24 -# endif - -# ifndef _ASM - typedef int __jmp_buf[6]; - - /* A `sigset_t' has a bit for each signal. */ -# define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int))) - typedef struct __sigset_t_tag - { - unsigned long int __val[_SIGSET_NWORDS]; - } __sigset_t; - - /* Calling environment, plus possibly a saved signal mask. */ - typedef struct __jmp_buf_tag /* C++ doesn't like tagless structs. */ - { - /* NOTE: The machine-dependent definitions of `__sigsetjmp' - assume that a `jmp_buf' begins with a `__jmp_buf' and that - `__mask_was_saved' follows it. Do not move these members - or add others before it. */ - __jmp_buf __jmpbuf; /* Calling environment. */ - int __mask_was_saved; /* Saved the signal mask? */ - // we never saved the mask. - __sigset_t __saved_mask; /* Saved signal mask. */ - } jmp_buf[1]; - - typedef jmp_buf sigjmp_buf; - typedef jmp_buf pj_jmp_buf; - - PJ_DECL(int) pj_setjmp(pj_jmp_buf env); - PJ_DECL(void) pj_longjmp(pj_jmp_buf env, int val) __attribute__((noreturn)); - -# endif /* _ASM */ - -#else -# warning "setjmp()/longjmp() is not implemented" - typedef int pj_jmp_buf[1]; -# define pj_setjmp(buf) 0 -# define pj_longjmp(buf,d) 0 -#endif - - -#endif /* __PJ_COMPAT_SETJMP_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/compat/setjmp.h 4 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/include/pj/compat/setjmp.h $ + * + * 4 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 3 9/22/05 10:31a Bennylp + * Moving all *.h files to include/. + * + * 2 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 1 9/17/05 10:36a Bennylp + * Created. + * + */ +#ifndef __PJ_COMPAT_SETJMP_H__ +#define __PJ_COMPAT_SETJMP_H__ + +/** + * @file setjmp.h + * @brief Provides setjmp.h functionality. + */ + +#if defined(PJ_HAS_SETJMP_H) && PJ_HAS_SETJMP_H != 0 +# include + typedef jmp_buf pj_jmp_buf; +# define pj_setjmp(buf) setjmp(buf) +# define pj_longjmp(buf,d) longjmp(buf,d) + +#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0 && \ + defined(PJ_M_I386) && PJ_M_I386 != 0 + + /* + * These are taken from uClibc. + * Copyright (C) 2000-2003 Erik Andersen + */ +# if defined __USE_MISC || defined _ASM +# define JB_BX 0 +# define JB_SI 1 +# define JB_DI 2 +# define JB_BP 3 +# define JB_SP 4 +# define JB_PC 5 +# define JB_SIZE 24 +# endif + +# ifndef _ASM + typedef int __jmp_buf[6]; + + /* A `sigset_t' has a bit for each signal. */ +# define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int))) + typedef struct __sigset_t_tag + { + unsigned long int __val[_SIGSET_NWORDS]; + } __sigset_t; + + /* Calling environment, plus possibly a saved signal mask. */ + typedef struct __jmp_buf_tag /* C++ doesn't like tagless structs. */ + { + /* NOTE: The machine-dependent definitions of `__sigsetjmp' + assume that a `jmp_buf' begins with a `__jmp_buf' and that + `__mask_was_saved' follows it. Do not move these members + or add others before it. */ + __jmp_buf __jmpbuf; /* Calling environment. */ + int __mask_was_saved; /* Saved the signal mask? */ + // we never saved the mask. + __sigset_t __saved_mask; /* Saved signal mask. */ + } jmp_buf[1]; + + typedef jmp_buf sigjmp_buf; + typedef jmp_buf pj_jmp_buf; + + PJ_DECL(int) pj_setjmp(pj_jmp_buf env); + PJ_DECL(void) pj_longjmp(pj_jmp_buf env, int val) __attribute__((noreturn)); + +# endif /* _ASM */ + +#else +# warning "setjmp()/longjmp() is not implemented" + typedef int pj_jmp_buf[1]; +# define pj_setjmp(buf) 0 +# define pj_longjmp(buf,d) 0 +#endif + + +#endif /* __PJ_COMPAT_SETJMP_H__ */ + diff --git a/pjlib/include/pj/compat/size_t.h b/pjlib/include/pj/compat/size_t.h index 39b41665..80064a76 100644 --- a/pjlib/include/pj/compat/size_t.h +++ b/pjlib/include/pj/compat/size_t.h @@ -1,23 +1,23 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/compat/size_t.h 2 9/21/05 1:39p Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/size_t.h $ - * - * 2 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_SIZE_T_H__ -#define __PJ_COMPAT_SIZE_T_H__ - -/** - * @file size_t.h - * @brief Provides size_t type. - */ -#if PJ_HAS_STDDEF_H -# include -#endif - -#endif /* __PJ_COMPAT_SIZE_T_H__ */ - +/* $Header: /pjproject-0.3/pjlib/src/pj/compat/size_t.h 2 9/21/05 1:39p Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/compat/size_t.h $ + * + * 2 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 1 9/17/05 10:36a Bennylp + * Created. + * + */ +#ifndef __PJ_COMPAT_SIZE_T_H__ +#define __PJ_COMPAT_SIZE_T_H__ + +/** + * @file size_t.h + * @brief Provides size_t type. + */ +#if PJ_HAS_STDDEF_H +# include +#endif + +#endif /* __PJ_COMPAT_SIZE_T_H__ */ + diff --git a/pjlib/include/pj/compat/socket.h b/pjlib/include/pj/compat/socket.h index 35befaea..561218b5 100644 --- a/pjlib/include/pj/compat/socket.h +++ b/pjlib/include/pj/compat/socket.h @@ -1,129 +1,129 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/compat/socket.h 5 10/29/05 11:51a Bennylp $*/ -/* $Log: /pjproject-0.3/pjlib/include/pj/compat/socket.h $ - * - * 5 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 4 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 3 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#ifndef __PJ_COMPAT_SOCKET_H__ -#define __PJ_COMPAT_SOCKET_H__ - -/** - * @file socket.h - * @brief Provides all socket related functions,data types, error codes, etc. - */ - -#if defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0 -# include -#endif - -#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0 -# include -#endif - -#if defined(PJ_HAS_SYS_TYPES_H) && PJ_HAS_SYS_TYPES_H != 0 -# include -#endif - -#if defined(PJ_HAS_SYS_SOCKET_H) && PJ_HAS_SYS_SOCKET_H != 0 -# include -#endif - -#if defined(PJ_HAS_LINUX_SOCKET_H) && PJ_HAS_LINUX_SOCKET_H != 0 -# include -#endif - -#if defined(PJ_HAS_SYS_SELECT_H) && PJ_HAS_SYS_SELECT_H != 0 -# include -#endif - -#if defined(PJ_HAS_NETINET_IN_H) && PJ_HAS_NETINET_IN_H != 0 -# include -#endif - -#if defined(PJ_HAS_ARPA_INET_H) && PJ_HAS_ARPA_INET_H != 0 -# include -#endif - -#if defined(PJ_HAS_SYS_IOCTL_H) && PJ_HAS_SYS_IOCTL_H != 0 -# include /* FBIONBIO */ -#endif - -#if defined(PJ_HAS_ERRNO_H) && PJ_HAS_ERRNO_H != 0 -# include -#endif - -#if defined(PJ_HAS_NETDB_H) && PJ_HAS_NETDB_H != 0 -# include -#endif - -#if defined(PJ_HAS_UNISTD_H) && PJ_HAS_UNISTD_H != 0 -# include -#endif - - -/* - * Define common errors. - */ -#ifdef PJ_WIN32 -# define OSERR_EWOULDBLOCK WSAEWOULDBLOCK -# define OSERR_EINPROGRESS WSAEINPROGRESS -#else -# define OSERR_EWOULDBLOCK EWOULDBLOCK -# define OSERR_EINPROGRESS EINPROGRESS -#endif - - -/* - * And undefine this.. - */ -#undef s_addr - -/* - * Linux kernel specifics - */ -#ifdef PJ_LINUX_KERNEL -# include -# include /* FIONBIO */ -# include /* sys_select() */ -# include /* set/get_fs() */ - - typedef int socklen_t; -# define getsockopt sys_getsockopt - - /* - * Wrapper for select() in Linux kernel. - */ - PJ_INLINE(int) select(int n, fd_set *inp, fd_set *outp, fd_set *exp, - struct timeval *tvp) - { - int count; - mm_segment_t oldfs = get_fs(); - set_fs(KERNEL_DS); - count = sys_select(n, inp, outp, exp, tvp); - set_fs(oldfs); - return count; - } -#endif /* PJ_LINUX_KERNEL */ - - -/* - * Windows specific - */ -#ifdef PJ_WIN32 - typedef int socklen_t;; -#endif - - -#endif /* __PJ_COMPAT_SOCKET_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/compat/socket.h 5 10/29/05 11:51a Bennylp $*/ +/* $Log: /pjproject-0.3/pjlib/include/pj/compat/socket.h $ + * + * 5 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 4 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 3 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 2 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#ifndef __PJ_COMPAT_SOCKET_H__ +#define __PJ_COMPAT_SOCKET_H__ + +/** + * @file socket.h + * @brief Provides all socket related functions,data types, error codes, etc. + */ + +#if defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0 +# include +#endif + +#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0 +# include +#endif + +#if defined(PJ_HAS_SYS_TYPES_H) && PJ_HAS_SYS_TYPES_H != 0 +# include +#endif + +#if defined(PJ_HAS_SYS_SOCKET_H) && PJ_HAS_SYS_SOCKET_H != 0 +# include +#endif + +#if defined(PJ_HAS_LINUX_SOCKET_H) && PJ_HAS_LINUX_SOCKET_H != 0 +# include +#endif + +#if defined(PJ_HAS_SYS_SELECT_H) && PJ_HAS_SYS_SELECT_H != 0 +# include +#endif + +#if defined(PJ_HAS_NETINET_IN_H) && PJ_HAS_NETINET_IN_H != 0 +# include +#endif + +#if defined(PJ_HAS_ARPA_INET_H) && PJ_HAS_ARPA_INET_H != 0 +# include +#endif + +#if defined(PJ_HAS_SYS_IOCTL_H) && PJ_HAS_SYS_IOCTL_H != 0 +# include /* FBIONBIO */ +#endif + +#if defined(PJ_HAS_ERRNO_H) && PJ_HAS_ERRNO_H != 0 +# include +#endif + +#if defined(PJ_HAS_NETDB_H) && PJ_HAS_NETDB_H != 0 +# include +#endif + +#if defined(PJ_HAS_UNISTD_H) && PJ_HAS_UNISTD_H != 0 +# include +#endif + + +/* + * Define common errors. + */ +#ifdef PJ_WIN32 +# define OSERR_EWOULDBLOCK WSAEWOULDBLOCK +# define OSERR_EINPROGRESS WSAEINPROGRESS +#else +# define OSERR_EWOULDBLOCK EWOULDBLOCK +# define OSERR_EINPROGRESS EINPROGRESS +#endif + + +/* + * And undefine this.. + */ +#undef s_addr + +/* + * Linux kernel specifics + */ +#ifdef PJ_LINUX_KERNEL +# include +# include /* FIONBIO */ +# include /* sys_select() */ +# include /* set/get_fs() */ + + typedef int socklen_t; +# define getsockopt sys_getsockopt + + /* + * Wrapper for select() in Linux kernel. + */ + PJ_INLINE(int) select(int n, fd_set *inp, fd_set *outp, fd_set *exp, + struct timeval *tvp) + { + int count; + mm_segment_t oldfs = get_fs(); + set_fs(KERNEL_DS); + count = sys_select(n, inp, outp, exp, tvp); + set_fs(oldfs); + return count; + } +#endif /* PJ_LINUX_KERNEL */ + + +/* + * Windows specific + */ +#ifdef PJ_WIN32 + typedef int socklen_t;; +#endif + + +#endif /* __PJ_COMPAT_SOCKET_H__ */ + diff --git a/pjlib/include/pj/compat/sprintf.h b/pjlib/include/pj/compat/sprintf.h index 7ecc929b..21353fb9 100644 --- a/pjlib/include/pj/compat/sprintf.h +++ b/pjlib/include/pj/compat/sprintf.h @@ -1,31 +1,31 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/compat/sprintf.h 2 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/include/pj/compat/sprintf.h $ - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_SPRINTF_H__ -#define __PJ_COMPAT_SPRINTF_H__ - -/** - * @file sprintf.h - * @brief Provides sprintf() and snprintf() functions. - */ - -#if defined(PJ_HAS_STDIO_H) && PJ_HAS_STDIO_H != 0 -# include -#endif - -#if defined(_MSC_VER) -# define snprintf _snprintf -#endif - -#define pj_sprintf sprintf -#define pj_snprintf snprintf - -#endif /* __PJ_COMPAT_SPRINTF_H__ */ +/* $Header: /pjproject-0.3/pjlib/include/pj/compat/sprintf.h 2 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/include/pj/compat/sprintf.h $ + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 9/17/05 10:36a Bennylp + * Created. + * + */ +#ifndef __PJ_COMPAT_SPRINTF_H__ +#define __PJ_COMPAT_SPRINTF_H__ + +/** + * @file sprintf.h + * @brief Provides sprintf() and snprintf() functions. + */ + +#if defined(PJ_HAS_STDIO_H) && PJ_HAS_STDIO_H != 0 +# include +#endif + +#if defined(_MSC_VER) +# define snprintf _snprintf +#endif + +#define pj_sprintf sprintf +#define pj_snprintf snprintf + +#endif /* __PJ_COMPAT_SPRINTF_H__ */ diff --git a/pjlib/include/pj/compat/stdarg.h b/pjlib/include/pj/compat/stdarg.h index 574cabb9..3c550ffc 100644 --- a/pjlib/include/pj/compat/stdarg.h +++ b/pjlib/include/pj/compat/stdarg.h @@ -1,20 +1,20 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/compat/stdarg.h 1 9/17/05 10:36a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/stdarg.h $ - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_STDARG_H__ -#define __PJ_COMPAT_STDARG_H__ - -/** - * @file stdarg.h - * @brief Provides stdarg functionality. - */ - -#if defined(PJ_HAS_STDARG_H) && PJ_HAS_STDARG_H != 0 -# include -#endif - -#endif /* __PJ_COMPAT_STDARG_H__ */ +/* $Header: /pjproject-0.3/pjlib/src/pj/compat/stdarg.h 1 9/17/05 10:36a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/compat/stdarg.h $ + * + * 1 9/17/05 10:36a Bennylp + * Created. + * + */ +#ifndef __PJ_COMPAT_STDARG_H__ +#define __PJ_COMPAT_STDARG_H__ + +/** + * @file stdarg.h + * @brief Provides stdarg functionality. + */ + +#if defined(PJ_HAS_STDARG_H) && PJ_HAS_STDARG_H != 0 +# include +#endif + +#endif /* __PJ_COMPAT_STDARG_H__ */ diff --git a/pjlib/include/pj/compat/stdfileio.h b/pjlib/include/pj/compat/stdfileio.h index 40b0c341..a9926a71 100644 --- a/pjlib/include/pj/compat/stdfileio.h +++ b/pjlib/include/pj/compat/stdfileio.h @@ -1,20 +1,20 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/compat/stdfileio.h 1 9/17/05 10:36a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/stdfileio.h $ - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_STDFILEIO_H__ -#define __PJ_COMPAT_STDFILEIO_H__ - -/** - * @file stdfileio.h - * @brief Compatibility for ANSI file I/O like fputs, fflush, etc. - */ - -#if defined(PJ_HAS_STDIO_H) && PJ_HAS_STDIO_H != 0 -# include -#endif - -#endif /* __PJ_COMPAT_STDFILEIO_H__ */ +/* $Header: /pjproject-0.3/pjlib/src/pj/compat/stdfileio.h 1 9/17/05 10:36a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/compat/stdfileio.h $ + * + * 1 9/17/05 10:36a Bennylp + * Created. + * + */ +#ifndef __PJ_COMPAT_STDFILEIO_H__ +#define __PJ_COMPAT_STDFILEIO_H__ + +/** + * @file stdfileio.h + * @brief Compatibility for ANSI file I/O like fputs, fflush, etc. + */ + +#if defined(PJ_HAS_STDIO_H) && PJ_HAS_STDIO_H != 0 +# include +#endif + +#endif /* __PJ_COMPAT_STDFILEIO_H__ */ diff --git a/pjlib/include/pj/compat/string.h b/pjlib/include/pj/compat/string.h index 86c8bd6b..3230fbdd 100644 --- a/pjlib/include/pj/compat/string.h +++ b/pjlib/include/pj/compat/string.h @@ -1,41 +1,41 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/compat/string.h 3 9/22/05 10:31a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/string.h $ - * - * 3 9/22/05 10:31a Bennylp - * Moving all *.h files to include/. - * - * 2 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_STRING_H__ -#define __PJ_COMPAT_STRING_H__ - -/** - * @file string.h - * @brief Provides string manipulation functions found in ANSI string.h. - */ - -#if defined(PJ_HAS_STRING_H) && PJ_HAS_STRING_H != 0 -# include -#else - - PJ_DECL(int) strcasecmp(const char *s1, const char *s2); - PJ_DECL(int) strncasecmp(const char *s1, const char *s2, int len); - -#endif - -#if defined(_MSC_VER) -# define strcasecmp stricmp -# define strncasecmp strnicmp -# define snprintf _snprintf -#else -# define stricmp strcasecmp -# define strnicmp strncasecmp -#endif - - -#endif /* __PJ_COMPAT_STRING_H__ */ +/* $Header: /pjproject-0.3/pjlib/src/pj/compat/string.h 3 9/22/05 10:31a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/compat/string.h $ + * + * 3 9/22/05 10:31a Bennylp + * Moving all *.h files to include/. + * + * 2 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 1 9/17/05 10:36a Bennylp + * Created. + * + */ +#ifndef __PJ_COMPAT_STRING_H__ +#define __PJ_COMPAT_STRING_H__ + +/** + * @file string.h + * @brief Provides string manipulation functions found in ANSI string.h. + */ + +#if defined(PJ_HAS_STRING_H) && PJ_HAS_STRING_H != 0 +# include +#else + + PJ_DECL(int) strcasecmp(const char *s1, const char *s2); + PJ_DECL(int) strncasecmp(const char *s1, const char *s2, int len); + +#endif + +#if defined(_MSC_VER) +# define strcasecmp stricmp +# define strncasecmp strnicmp +# define snprintf _snprintf +#else +# define stricmp strcasecmp +# define strnicmp strncasecmp +#endif + + +#endif /* __PJ_COMPAT_STRING_H__ */ diff --git a/pjlib/include/pj/compat/time.h b/pjlib/include/pj/compat/time.h index 45585cb1..f76c1e41 100644 --- a/pjlib/include/pj/compat/time.h +++ b/pjlib/include/pj/compat/time.h @@ -1,25 +1,25 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/compat/time.h 1 9/17/05 10:36a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/time.h $ - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_TIME_H__ -#define __PJ_COMPAT_TIME_H__ - -/** - * @file time.h - * @brief Provides ftime() and localtime() etc functions. - */ - -#if defined(PJ_HAS_TIME_H) && PJ_HAS_TIME_H != 0 -# include -#endif - -#if defined(PJ_HAS_SYS_TIMEB_H) && PJ_HAS_SYS_TIMEB_H != 0 -# include -#endif - - -#endif /* __PJ_COMPAT_TIME_H__ */ +/* $Header: /pjproject-0.3/pjlib/src/pj/compat/time.h 1 9/17/05 10:36a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/compat/time.h $ + * + * 1 9/17/05 10:36a Bennylp + * Created. + * + */ +#ifndef __PJ_COMPAT_TIME_H__ +#define __PJ_COMPAT_TIME_H__ + +/** + * @file time.h + * @brief Provides ftime() and localtime() etc functions. + */ + +#if defined(PJ_HAS_TIME_H) && PJ_HAS_TIME_H != 0 +# include +#endif + +#if defined(PJ_HAS_SYS_TIMEB_H) && PJ_HAS_SYS_TIMEB_H != 0 +# include +#endif + + +#endif /* __PJ_COMPAT_TIME_H__ */ diff --git a/pjlib/include/pj/compat/vsprintf.h b/pjlib/include/pj/compat/vsprintf.h index 3d2bd341..cc93bc55 100644 --- a/pjlib/include/pj/compat/vsprintf.h +++ b/pjlib/include/pj/compat/vsprintf.h @@ -1,26 +1,26 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/compat/vsprintf.h 1 9/17/05 10:36a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/vsprintf.h $ - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#ifndef __PJ_COMPAT_VSPRINTF_H__ -#define __PJ_COMPAT_VSPRINTF_H__ - -/** - * @file vsprintf.h - * @brief Provides vsprintf and vsnprintf function. - */ - -#if defined(PJ_HAS_STDIO_H) && PJ_HAS_STDIO_H != 0 -# include -#endif - -#if defined(_MSC_VER) -# define vsnprintf _vsnprintf -#endif - -#define pj_vsnprintf vsnprintf - -#endif /* __PJ_COMPAT_VSPRINTF_H__ */ +/* $Header: /pjproject-0.3/pjlib/src/pj/compat/vsprintf.h 1 9/17/05 10:36a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/compat/vsprintf.h $ + * + * 1 9/17/05 10:36a Bennylp + * Created. + * + */ +#ifndef __PJ_COMPAT_VSPRINTF_H__ +#define __PJ_COMPAT_VSPRINTF_H__ + +/** + * @file vsprintf.h + * @brief Provides vsprintf and vsnprintf function. + */ + +#if defined(PJ_HAS_STDIO_H) && PJ_HAS_STDIO_H != 0 +# include +#endif + +#if defined(_MSC_VER) +# define vsnprintf _vsnprintf +#endif + +#define pj_vsnprintf vsnprintf + +#endif /* __PJ_COMPAT_VSPRINTF_H__ */ diff --git a/pjlib/include/pj/config.h b/pjlib/include/pj/config.h index 3c093b8b..fd80e86f 100644 --- a/pjlib/include/pj/config.h +++ b/pjlib/include/pj/config.h @@ -1,438 +1,442 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/config.h 12 10/29/05 10:25p Bennylp $ */ - -#ifndef __PJ_CONFIG_H__ -#define __PJ_CONFIG_H__ - -/** - * @file config.h - * @brief PJLIB Main configuration settings. - */ - -/******************************************************************** - * Include compiler specific configuration. - */ -#if defined(_MSC_VER) -# include -#elif defined(__GNUC__) -# include -#else -# error "Unknown compiler." -#endif - - -/******************************************************************** - * Include target specific configuration. - */ -#if defined(PJ_WIN32) -# include -#elif defined(PJ_LINUX) -# include -#elif defined(PJ_LINUX_KERNEL) -# include -#elif defined(PJ_PALMOS) -# include -#else -# error "Please specify target os." -#endif - - -/******************************************************************** - * Target machine specific configuration. - */ -#if defined (PJ_M_I386) && PJ_M_I386 != 0 -# include -#elif defined (PJ_M_M68K) && PJ_M_M68K != 0 -# include -#elif defined (PJ_M_ALPHA) && PJ_M_ALPHA != 0 -# include -#else -# error "Please specify target machine." -#endif - -/* Include size_t definition. */ -#include - -/* Include site/user specific configuration to control PJLIB features. - * YOU MUST CREATE THIS FILE YOURSELF!! - */ -#include - -/******************************************************************** - * PJLIB Features. - */ - -/* Overrides for DOXYGEN */ -#ifdef DOXYGEN -# undef PJ_FUNCTIONS_ARE_INLINED -# undef PJ_HAS_FLOATING_POINT -# undef PJ_LOG_MAX_LEVEL -# undef PJ_LOG_MAX_SIZE -# undef PJ_LOG_USE_STACK_BUFFER -# undef PJ_TERM_HAS_COLOR -# undef PJ_POOL_DEBUG -# undef PJ_HAS_TCP -# undef PJ_MAX_HOSTNAME -# undef PJ_IOQUEUE_MAX_HANDLES -# undef FD_SETSIZE -# undef PJ_HAS_SEMAPHORE -# undef PJ_HAS_EVENT_OBJ -# undef PJ_ENABLE_EXTRA_CHECK -#endif - -/** - * @defgroup pj_config Build Configuration - * @ingroup PJ - * @{ - * - * This section contains macros that can set during PJLIB build process - * to controll various aspects of the library. - * - * Note: the values in this page does NOT necessarily reflect to the - * macro values during the build process. - */ - -/** - * If this macro is set to 1, it will enable some debugging checking - * in the library. - * - * Default: equal to (NOT NDEBUG). - */ -#ifndef PJ_DEBUG -# ifndef NDEBUG -# define PJ_DEBUG 1 -# else -# define PJ_DEBUG 0 -# endif -#endif - -/** - * Expand functions in *_i.h header files as inline. - * - * Default: 0. - */ -#ifndef PJ_FUNCTIONS_ARE_INLINED -# define PJ_FUNCTIONS_ARE_INLINED 0 -#endif - -/** - * Use floating point computations in the library. - * - * Default: 1. - */ -#ifndef PJ_HAS_FLOATING_POINT -# define PJ_HAS_FLOATING_POINT 1 -#endif - -/** - * Declare maximum logging level/verbosity. Lower number indicates higher - * importance, with the highest importance has level zero. The least - * important level is five in this implementation, but this can be extended - * by supplying the appropriate implementation. - * - * The level conventions: - * - 0: fatal error - * - 1: error - * - 2: warning - * - 3: info - * - 4: debug - * - 5: trace - * - 6: more detailed trace - * - * Default: 4 - */ -#ifndef PJ_LOG_MAX_LEVEL -# define PJ_LOG_MAX_LEVEL 4 -#endif - -/** - * Maximum message size that can be sent to output device for each call - * to PJ_LOG(). If the message size is longer than this value, it will be cut. - * This may affect the stack usage, depending whether PJ_LOG_USE_STACK_BUFFER - * flag is set. - * - * Default: 800 - */ -#ifndef PJ_LOG_MAX_SIZE -# define PJ_LOG_MAX_SIZE 800 -#endif - -/** - * Log buffer. - * Does the log get the buffer from the stack? (default is yes). - * If the value is set to NO, then the buffer will be taken from static - * buffer, which in this case will make the log function non-reentrant. - * - * Default: 1 - */ -#ifndef PJ_LOG_USE_STACK_BUFFER -# define PJ_LOG_USE_STACK_BUFFER 1 -#endif - - -/** - * Colorfull terminal (for logging etc). - * - * Default: 1 - */ -#ifndef PJ_TERM_HAS_COLOR -# define PJ_TERM_HAS_COLOR 1 -#endif - -/** - * Pool debugging. - * - * Default: 0 - */ -#ifndef PJ_POOL_DEBUG -# define PJ_POOL_DEBUG 0 -#endif - -/** - * \def PJ_HAS_TCP - * Support TCP in the library. - * Disabling TCP will reduce the footprint slightly (about 6KB). - * - * Default: 1 - */ -#ifndef PJ_HAS_TCP -# define PJ_HAS_TCP 1 -#endif - -/** - * Maximum hostname length. - * Libraries sometimes needs to make copy of an address to stack buffer; - * the value here affects the stack usage. - * - * Default: 128 - */ -#ifndef PJ_MAX_HOSTNAME -# define PJ_MAX_HOSTNAME (128) -#endif - -/** - * Constants for declaring the maximum handles that can be supported by - * a single IOQ framework. This constant might not be relevant to the - * underlying I/O queue impelementation, but still, developers should be - * aware of this constant, to make sure that the program will not break when - * the underlying implementation changes. - * - * For implementation based on select(), the value here will be used as the - * maximum number of socket handles passed to select() (i.e. FD_SETSIZE will - * be set to this value). - * - * Default: 64 - */ -#ifndef PJ_IOQUEUE_MAX_HANDLES -# define PJ_IOQUEUE_MAX_HANDLES (64) -#endif - -/** - * Overrides FD_SETSIZE so it is consistent throughout the library. - * OS specific configuration header (compat/os_*) might have declared - * FD_SETSIZE, thus we only set if it hasn't been declared. - * - * Default: #PJ_IOQUEUE_MAX_HANDLES - */ -#ifndef FD_SETSIZE -# define FD_SETSIZE PJ_IOQUEUE_MAX_HANDLES -#endif - -/** - * Has semaphore functionality? - * - * Default: 1 - */ -#ifndef PJ_HAS_SEMAPHORE -# define PJ_HAS_SEMAPHORE 1 -#endif - - -/** - * Event object (for synchronization, e.g. in Win32) - * - * Default: 1 - */ -#ifndef PJ_HAS_EVENT_OBJ -# define PJ_HAS_EVENT_OBJ 1 -#endif - - -/** - * Enable library's extra check. - * If this macro is enabled, #PJ_ASSERT_RETURN macro will expand to - * run-time checking. If this macro is disabled, #PJ_ASSERT_RETURN - * will simply evaluate to #pj_assert(). - * - * You can disable this macro to reduce size, at the risk of crashes - * if invalid value (e.g. NULL) is passed to the library. - * - * Default: 1 - */ -#ifndef PJ_ENABLE_EXTRA_CHECK -# define PJ_ENABLE_EXTRA_CHECK 1 -#endif - - -/** - * Enable name registration for exceptions with #pj_exception_id_alloc(). - * If this feature is enabled, then the library will keep track of - * names associated with each exception ID requested by application via - * #pj_exception_id_alloc(). - * - * Disabling this macro will reduce the code and .bss size by a tad bit. - * See also #PJ_MAX_EXCEPTION_ID. - * - * Default: 1 - */ -#ifndef PJ_HAS_EXCEPTION_NAMES -# define PJ_HAS_EXCEPTION_NAMES 1 -#endif - -/** - * Maximum number of unique exception IDs that can be requested - * with #pj_exception_id_alloc(). For each entry, a small record will - * be allocated in the .bss segment. - * - * Default: 16 - */ -#ifndef PJ_MAX_EXCEPTION_ID -# define PJ_MAX_EXCEPTION_ID 16 -#endif - -/** @} */ - -/******************************************************************** - * General macros. - */ - -/** - * @def PJ_INLINE(type) - * @param type The return type of the function. - * Expand the function as inline. - */ -#define PJ_INLINE(type) PJ_INLINE_SPECIFIER type - -/** - * @def PJ_DECL(type) - * @param type The return type of the function. - * Declare a function. - */ -/** - * @def PJ_DECL_NO_RETURN(type) - * @param type The return type of the function. - * Declare a function that will not return. - */ -/** - * @def PJ_BEGIN_DECL - * Mark beginning of declaration section in a header file. - */ -/** - * @def PJ_END_DECL - * Mark end of declaration section in a header file. - */ -#ifdef __cplusplus -# define PJ_DECL(type) type -# define PJ_DECL_NO_RETURN(type) type PJ_NORETURN -# define PJ_BEGIN_DECL extern "C" { -# define PJ_END_DECL } -#else -# define PJ_DECL(type) extern type -# define PJ_DECL_NO_RETURN(type) PJ_NORETURN type -# define PJ_BEGIN_DECL -# define PJ_END_DECL -#endif - -/** - * @def PJ_DEF(type) - * @param type The return type of the function. - * Define a function. - */ -#define PJ_DEF(type) type - -/** - * @def PJ_EXPORT_SYMBOL(sym) - * @param sym The symbol to export. - * Export the specified symbol in compilation type that requires export - * (e.g. Linux kernel). - */ -#ifdef __PJ_EXPORT_SYMBOL -# define PJ_EXPORT_SYMBOL(sym) __PJ_EXPORT_SYMBOL(sym) -#else -# define PJ_EXPORT_SYMBOL(sym) -#endif - -/** - * @def PJ_IDECL(type) - * @param type The function's return type. - * Declare a function that may be expanded as inline. - */ -/** - * @def PJ_IDEF(type) - * @param type The function's return type. - * Define a function that may be expanded as inline. - */ - -#if PJ_FUNCTIONS_ARE_INLINED -# define PJ_IDECL(type) PJ_INLINE(type) -# define PJ_IDEF(type) PJ_INLINE(type) -#else -# define PJ_IDECL(type) PJ_DECL(type) -# define PJ_IDEF(type) PJ_DEF(type) -#endif - -/** - * @def PJ_UNUSED_ARG(arg) - * @param arg The argument name. - * PJ_UNUSED_ARG prevents warning about unused argument in a function. - */ -#define PJ_UNUSED_ARG(arg) (void)arg - -/** - * @def PJ_TODO(id) - * @param id Any identifier that will be printed as TODO message. - * PJ_TODO macro will display TODO message as warning during compilation. - * Example: PJ_TODO(CLEAN_UP_ERROR); - */ -#ifndef PJ_TODO -# define PJ_TODO(id) TODO___##id: -#endif - - -/******************************************************************** - * Sanity Checks - */ -#ifndef PJ_HAS_HIGH_RES_TIMER -# error "PJ_HAS_HIGH_RES_TIMER is not defined!" -#endif - -#if !defined(PJ_HAS_PENTIUM) -# error "PJ_HAS_PENTIUM is not defined!" -#endif - -#if !defined(PJ_IS_LITTLE_ENDIAN) -# error "PJ_IS_LITTLE_ENDIAN is not defined!" -#endif - -#if !defined(PJ_IS_BIG_ENDIAN) -# error "PJ_IS_BIG_ENDIAN is not defined!" -#endif - - - -PJ_BEGIN_DECL - -/** - * PJLIB version string. - */ -extern const char *PJ_VERSION; - -/** - * Dump configuration to log with verbosity equal to info(3). - */ -PJ_DECL(void) pj_dump_config(void); - -PJ_END_DECL - - -#endif /* __PJ_CONFIG_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/config.h 12 10/29/05 10:25p Bennylp $ */ + +#ifndef __PJ_CONFIG_H__ +#define __PJ_CONFIG_H__ + +/** + * @file config.h + * @brief PJLIB Main configuration settings. + */ + +/******************************************************************** + * Include compiler specific configuration. + */ +#if defined(_MSC_VER) +# include +#elif defined(__GNUC__) +# include +#else +# error "Unknown compiler." +#endif + + +/******************************************************************** + * Include target OS specific configuration. + */ +#if defined(PJ_WIN32) && PJ_WIN32!=0 +# include +#elif defined(PJ_LINUX) && PJ_LINUX!=0 +# include +#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL!=0 +# include +#elif defined(PJ_PALMOS) && PJ_PALMOS!=0 +# include +#elif defined(PJ_SUNOS) && PJ_SUNOS!=0 +# include +#else +# error "Please specify target os." +#endif + + +/******************************************************************** + * Target machine specific configuration. + */ +#if defined (PJ_M_I386) && PJ_M_I386 != 0 +# include +#elif defined (PJ_M_M68K) && PJ_M_M68K != 0 +# include +#elif defined (PJ_M_ALPHA) && PJ_M_ALPHA != 0 +# include +#elif defined (PJ_M_SPARC) && PJ_M_SPARC != 0 +# include +#else +# error "Please specify target machine." +#endif + +/* Include size_t definition. */ +#include + +/* Include site/user specific configuration to control PJLIB features. + * YOU MUST CREATE THIS FILE YOURSELF!! + */ +#include + +/******************************************************************** + * PJLIB Features. + */ + +/* Overrides for DOXYGEN */ +#ifdef DOXYGEN +# undef PJ_FUNCTIONS_ARE_INLINED +# undef PJ_HAS_FLOATING_POINT +# undef PJ_LOG_MAX_LEVEL +# undef PJ_LOG_MAX_SIZE +# undef PJ_LOG_USE_STACK_BUFFER +# undef PJ_TERM_HAS_COLOR +# undef PJ_POOL_DEBUG +# undef PJ_HAS_TCP +# undef PJ_MAX_HOSTNAME +# undef PJ_IOQUEUE_MAX_HANDLES +# undef FD_SETSIZE +# undef PJ_HAS_SEMAPHORE +# undef PJ_HAS_EVENT_OBJ +# undef PJ_ENABLE_EXTRA_CHECK +#endif + +/** + * @defgroup pj_config Build Configuration + * @ingroup PJ + * @{ + * + * This section contains macros that can set during PJLIB build process + * to controll various aspects of the library. + * + * Note: the values in this page does NOT necessarily reflect to the + * macro values during the build process. + */ + +/** + * If this macro is set to 1, it will enable some debugging checking + * in the library. + * + * Default: equal to (NOT NDEBUG). + */ +#ifndef PJ_DEBUG +# ifndef NDEBUG +# define PJ_DEBUG 1 +# else +# define PJ_DEBUG 0 +# endif +#endif + +/** + * Expand functions in *_i.h header files as inline. + * + * Default: 0. + */ +#ifndef PJ_FUNCTIONS_ARE_INLINED +# define PJ_FUNCTIONS_ARE_INLINED 0 +#endif + +/** + * Use floating point computations in the library. + * + * Default: 1. + */ +#ifndef PJ_HAS_FLOATING_POINT +# define PJ_HAS_FLOATING_POINT 1 +#endif + +/** + * Declare maximum logging level/verbosity. Lower number indicates higher + * importance, with the highest importance has level zero. The least + * important level is five in this implementation, but this can be extended + * by supplying the appropriate implementation. + * + * The level conventions: + * - 0: fatal error + * - 1: error + * - 2: warning + * - 3: info + * - 4: debug + * - 5: trace + * - 6: more detailed trace + * + * Default: 4 + */ +#ifndef PJ_LOG_MAX_LEVEL +# define PJ_LOG_MAX_LEVEL 4 +#endif + +/** + * Maximum message size that can be sent to output device for each call + * to PJ_LOG(). If the message size is longer than this value, it will be cut. + * This may affect the stack usage, depending whether PJ_LOG_USE_STACK_BUFFER + * flag is set. + * + * Default: 800 + */ +#ifndef PJ_LOG_MAX_SIZE +# define PJ_LOG_MAX_SIZE 800 +#endif + +/** + * Log buffer. + * Does the log get the buffer from the stack? (default is yes). + * If the value is set to NO, then the buffer will be taken from static + * buffer, which in this case will make the log function non-reentrant. + * + * Default: 1 + */ +#ifndef PJ_LOG_USE_STACK_BUFFER +# define PJ_LOG_USE_STACK_BUFFER 1 +#endif + + +/** + * Colorfull terminal (for logging etc). + * + * Default: 1 + */ +#ifndef PJ_TERM_HAS_COLOR +# define PJ_TERM_HAS_COLOR 1 +#endif + +/** + * Pool debugging. + * + * Default: 0 + */ +#ifndef PJ_POOL_DEBUG +# define PJ_POOL_DEBUG 0 +#endif + +/** + * \def PJ_HAS_TCP + * Support TCP in the library. + * Disabling TCP will reduce the footprint slightly (about 6KB). + * + * Default: 1 + */ +#ifndef PJ_HAS_TCP +# define PJ_HAS_TCP 1 +#endif + +/** + * Maximum hostname length. + * Libraries sometimes needs to make copy of an address to stack buffer; + * the value here affects the stack usage. + * + * Default: 128 + */ +#ifndef PJ_MAX_HOSTNAME +# define PJ_MAX_HOSTNAME (128) +#endif + +/** + * Constants for declaring the maximum handles that can be supported by + * a single IOQ framework. This constant might not be relevant to the + * underlying I/O queue impelementation, but still, developers should be + * aware of this constant, to make sure that the program will not break when + * the underlying implementation changes. + * + * For implementation based on select(), the value here will be used as the + * maximum number of socket handles passed to select() (i.e. FD_SETSIZE will + * be set to this value). + * + * Default: 64 + */ +#ifndef PJ_IOQUEUE_MAX_HANDLES +# define PJ_IOQUEUE_MAX_HANDLES (64) +#endif + +/** + * Overrides FD_SETSIZE so it is consistent throughout the library. + * OS specific configuration header (compat/os_*) might have declared + * FD_SETSIZE, thus we only set if it hasn't been declared. + * + * Default: #PJ_IOQUEUE_MAX_HANDLES + */ +#ifndef FD_SETSIZE +# define FD_SETSIZE PJ_IOQUEUE_MAX_HANDLES +#endif + +/** + * Has semaphore functionality? + * + * Default: 1 + */ +#ifndef PJ_HAS_SEMAPHORE +# define PJ_HAS_SEMAPHORE 1 +#endif + + +/** + * Event object (for synchronization, e.g. in Win32) + * + * Default: 1 + */ +#ifndef PJ_HAS_EVENT_OBJ +# define PJ_HAS_EVENT_OBJ 1 +#endif + + +/** + * Enable library's extra check. + * If this macro is enabled, #PJ_ASSERT_RETURN macro will expand to + * run-time checking. If this macro is disabled, #PJ_ASSERT_RETURN + * will simply evaluate to #pj_assert(). + * + * You can disable this macro to reduce size, at the risk of crashes + * if invalid value (e.g. NULL) is passed to the library. + * + * Default: 1 + */ +#ifndef PJ_ENABLE_EXTRA_CHECK +# define PJ_ENABLE_EXTRA_CHECK 1 +#endif + + +/** + * Enable name registration for exceptions with #pj_exception_id_alloc(). + * If this feature is enabled, then the library will keep track of + * names associated with each exception ID requested by application via + * #pj_exception_id_alloc(). + * + * Disabling this macro will reduce the code and .bss size by a tad bit. + * See also #PJ_MAX_EXCEPTION_ID. + * + * Default: 1 + */ +#ifndef PJ_HAS_EXCEPTION_NAMES +# define PJ_HAS_EXCEPTION_NAMES 1 +#endif + +/** + * Maximum number of unique exception IDs that can be requested + * with #pj_exception_id_alloc(). For each entry, a small record will + * be allocated in the .bss segment. + * + * Default: 16 + */ +#ifndef PJ_MAX_EXCEPTION_ID +# define PJ_MAX_EXCEPTION_ID 16 +#endif + +/** @} */ + +/******************************************************************** + * General macros. + */ + +/** + * @def PJ_INLINE(type) + * @param type The return type of the function. + * Expand the function as inline. + */ +#define PJ_INLINE(type) PJ_INLINE_SPECIFIER type + +/** + * @def PJ_DECL(type) + * @param type The return type of the function. + * Declare a function. + */ +/** + * @def PJ_DECL_NO_RETURN(type) + * @param type The return type of the function. + * Declare a function that will not return. + */ +/** + * @def PJ_BEGIN_DECL + * Mark beginning of declaration section in a header file. + */ +/** + * @def PJ_END_DECL + * Mark end of declaration section in a header file. + */ +#ifdef __cplusplus +# define PJ_DECL(type) type +# define PJ_DECL_NO_RETURN(type) type PJ_NORETURN +# define PJ_BEGIN_DECL extern "C" { +# define PJ_END_DECL } +#else +# define PJ_DECL(type) extern type +# define PJ_DECL_NO_RETURN(type) PJ_NORETURN type +# define PJ_BEGIN_DECL +# define PJ_END_DECL +#endif + +/** + * @def PJ_DEF(type) + * @param type The return type of the function. + * Define a function. + */ +#define PJ_DEF(type) type + +/** + * @def PJ_EXPORT_SYMBOL(sym) + * @param sym The symbol to export. + * Export the specified symbol in compilation type that requires export + * (e.g. Linux kernel). + */ +#ifdef __PJ_EXPORT_SYMBOL +# define PJ_EXPORT_SYMBOL(sym) __PJ_EXPORT_SYMBOL(sym) +#else +# define PJ_EXPORT_SYMBOL(sym) +#endif + +/** + * @def PJ_IDECL(type) + * @param type The function's return type. + * Declare a function that may be expanded as inline. + */ +/** + * @def PJ_IDEF(type) + * @param type The function's return type. + * Define a function that may be expanded as inline. + */ + +#if PJ_FUNCTIONS_ARE_INLINED +# define PJ_IDECL(type) PJ_INLINE(type) +# define PJ_IDEF(type) PJ_INLINE(type) +#else +# define PJ_IDECL(type) PJ_DECL(type) +# define PJ_IDEF(type) PJ_DEF(type) +#endif + +/** + * @def PJ_UNUSED_ARG(arg) + * @param arg The argument name. + * PJ_UNUSED_ARG prevents warning about unused argument in a function. + */ +#define PJ_UNUSED_ARG(arg) (void)arg + +/** + * @def PJ_TODO(id) + * @param id Any identifier that will be printed as TODO message. + * PJ_TODO macro will display TODO message as warning during compilation. + * Example: PJ_TODO(CLEAN_UP_ERROR); + */ +#ifndef PJ_TODO +# define PJ_TODO(id) TODO___##id: +#endif + + +/******************************************************************** + * Sanity Checks + */ +#ifndef PJ_HAS_HIGH_RES_TIMER +# error "PJ_HAS_HIGH_RES_TIMER is not defined!" +#endif + +#if !defined(PJ_HAS_PENTIUM) +# error "PJ_HAS_PENTIUM is not defined!" +#endif + +#if !defined(PJ_IS_LITTLE_ENDIAN) +# error "PJ_IS_LITTLE_ENDIAN is not defined!" +#endif + +#if !defined(PJ_IS_BIG_ENDIAN) +# error "PJ_IS_BIG_ENDIAN is not defined!" +#endif + + + +PJ_BEGIN_DECL + +/** + * PJLIB version string. + */ +extern const char *PJ_VERSION; + +/** + * Dump configuration to log with verbosity equal to info(3). + */ +PJ_DECL(void) pj_dump_config(void); + +PJ_END_DECL + + +#endif /* __PJ_CONFIG_H__ */ + diff --git a/pjlib/include/pj/ctype.h b/pjlib/include/pj/ctype.h index 943034f6..4df689ce 100644 --- a/pjlib/include/pj/ctype.h +++ b/pjlib/include/pj/ctype.h @@ -1,119 +1,119 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/ctype.h 4 10/14/05 12:26a Bennylp $ */ -#ifndef __PJ_CTYPE_H__ -#define __PJ_CTYPE_H__ - -/** - * @file ctype.h - * @brief C type helper macros. - */ - -#include - -/** - * @defgroup pj_ctype ctype - Character Type - * @ingroup PJ_MISC - * @{ - * - * This module contains several inline functions/macros for testing or - * manipulating character types. It is provided in PJLIB because PJLIB - * must not depend to LIBC. - */ - -/** - * Returns a non-zero value if either isalpha or isdigit is true for c. - * @param c The integer character to test. - * @return Non-zero value if either isalpha or isdigit is true for c. - */ -PJ_INLINE(int) pj_isalnum(int c) { return isalnum(c); } - -/** - * Returns a non-zero value if c is a particular representation of an - * alphabetic character. - * @param c The integer character to test. - * @return Non-zero value if c is a particular representation of an - * alphabetic character. - */ -PJ_INLINE(int) pj_isalpha(int c) { return isalpha(c); } - -/** - * Returns a non-zero value if c is a particular representation of an - * ASCII character. - * @param c The integer character to test. - * @return Non-zero value if c is a particular representation of - * an ASCII character. - */ -PJ_INLINE(int) pj_isascii(int c) { return isascii(c); } - -/** - * Returns a non-zero value if c is a particular representation of - * a decimal-digit character. - * @param c The integer character to test. - * @return Non-zero value if c is a particular representation of - * a decimal-digit character. - */ -PJ_INLINE(int) pj_isdigit(int c) { return isdigit(c); } - -/** - * Returns a non-zero value if c is a particular representation of - * a space character (0x09 - 0x0D or 0x20). - * @param c The integer character to test. - * @return Non-zero value if c is a particular representation of - * a space character (0x09 - 0x0D or 0x20). - */ -PJ_INLINE(int) pj_isspace(int c) { return isspace(c); } - -/** - * Returns a non-zero value if c is a particular representation of - * a lowercase character. - * @param c The integer character to test. - * @return Non-zero value if c is a particular representation of - * a lowercase character. - */ -PJ_INLINE(int) pj_islower(int c) { return islower(c); } - - -/** - * Returns a non-zero value if c is a particular representation of - * a uppercase character. - * @param c The integer character to test. - * @return Non-zero value if c is a particular representation of - * a uppercase character. - */ -PJ_INLINE(int) pj_isupper(int c) { return isupper(c); } - -/** - * Returns a non-zero value if c is a particular representation of - * an hexadecimal digit character. - * @param c The integer character to test. - * @return Non-zero value if c is a particular representation of - * an hexadecimal digit character. - */ -PJ_INLINE(int) pj_isxdigit(int c){ return isxdigit(c); } - -/** - * Returns a non-zero value if c is a either a space (' ') or horizontal - * tab ('\\t') character. - * @param c The integer character to test. - * @return Non-zero value if c is a either a space (' ') or horizontal - * tab ('\\t') character. - */ -PJ_INLINE(int) pj_isblank(int c) { return isblank(c); } - -/** - * Converts character to lowercase. - * @param c The integer character to convert. - * @return Lowercase character of c. - */ -PJ_INLINE(int) pj_tolower(int c) { return tolower(c); } - -/** - * Converts character to uppercase. - * @param c The integer character to convert. - * @return Uppercase character of c. - */ -PJ_INLINE(int) pj_toupper(int c) { return toupper(c); } - -/** @} */ - -#endif /* __PJ_CTYPE_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/ctype.h 4 10/14/05 12:26a Bennylp $ */ +#ifndef __PJ_CTYPE_H__ +#define __PJ_CTYPE_H__ + +/** + * @file ctype.h + * @brief C type helper macros. + */ + +#include + +/** + * @defgroup pj_ctype ctype - Character Type + * @ingroup PJ_MISC + * @{ + * + * This module contains several inline functions/macros for testing or + * manipulating character types. It is provided in PJLIB because PJLIB + * must not depend to LIBC. + */ + +/** + * Returns a non-zero value if either isalpha or isdigit is true for c. + * @param c The integer character to test. + * @return Non-zero value if either isalpha or isdigit is true for c. + */ +PJ_INLINE(int) pj_isalnum(int c) { return isalnum(c); } + +/** + * Returns a non-zero value if c is a particular representation of an + * alphabetic character. + * @param c The integer character to test. + * @return Non-zero value if c is a particular representation of an + * alphabetic character. + */ +PJ_INLINE(int) pj_isalpha(int c) { return isalpha(c); } + +/** + * Returns a non-zero value if c is a particular representation of an + * ASCII character. + * @param c The integer character to test. + * @return Non-zero value if c is a particular representation of + * an ASCII character. + */ +PJ_INLINE(int) pj_isascii(int c) { return isascii(c); } + +/** + * Returns a non-zero value if c is a particular representation of + * a decimal-digit character. + * @param c The integer character to test. + * @return Non-zero value if c is a particular representation of + * a decimal-digit character. + */ +PJ_INLINE(int) pj_isdigit(int c) { return isdigit(c); } + +/** + * Returns a non-zero value if c is a particular representation of + * a space character (0x09 - 0x0D or 0x20). + * @param c The integer character to test. + * @return Non-zero value if c is a particular representation of + * a space character (0x09 - 0x0D or 0x20). + */ +PJ_INLINE(int) pj_isspace(int c) { return isspace(c); } + +/** + * Returns a non-zero value if c is a particular representation of + * a lowercase character. + * @param c The integer character to test. + * @return Non-zero value if c is a particular representation of + * a lowercase character. + */ +PJ_INLINE(int) pj_islower(int c) { return islower(c); } + + +/** + * Returns a non-zero value if c is a particular representation of + * a uppercase character. + * @param c The integer character to test. + * @return Non-zero value if c is a particular representation of + * a uppercase character. + */ +PJ_INLINE(int) pj_isupper(int c) { return isupper(c); } + +/** + * Returns a non-zero value if c is a particular representation of + * an hexadecimal digit character. + * @param c The integer character to test. + * @return Non-zero value if c is a particular representation of + * an hexadecimal digit character. + */ +PJ_INLINE(int) pj_isxdigit(int c){ return isxdigit(c); } + +/** + * Returns a non-zero value if c is a either a space (' ') or horizontal + * tab ('\\t') character. + * @param c The integer character to test. + * @return Non-zero value if c is a either a space (' ') or horizontal + * tab ('\\t') character. + */ +PJ_INLINE(int) pj_isblank(int c) { return isblank(c); } + +/** + * Converts character to lowercase. + * @param c The integer character to convert. + * @return Lowercase character of c. + */ +PJ_INLINE(int) pj_tolower(int c) { return tolower(c); } + +/** + * Converts character to uppercase. + * @param c The integer character to convert. + * @return Uppercase character of c. + */ +PJ_INLINE(int) pj_toupper(int c) { return toupper(c); } + +/** @} */ + +#endif /* __PJ_CTYPE_H__ */ + diff --git a/pjlib/include/pj/doxygen.h b/pjlib/include/pj/doxygen.h index c6732653..cda0517b 100644 --- a/pjlib/include/pj/doxygen.h +++ b/pjlib/include/pj/doxygen.h @@ -1,880 +1,880 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/doxygen.h 5 10/29/05 10:27p Bennylp $ */ -#ifndef __PJ_DOXYGEN_H__ -#define __PJ_DOXYGEN_H__ - -/** - * @file doxygen.h - * @brief Doxygen's mainpage. - */ - -/*//////////////////////////////////////////////////////////////////////////*/ -/* - INTRODUCTION PAGE - */ - -/** - * @mainpage Welcome to PJLIB! - * - * @section intro_sec What is PJLIB - * - * PJLIB is a small foundation library written in C for making scalable - * applications. Because of its small footprint, it can be used in embedded - * applications (we hope so!), but yet the library is also aimed for - * facilitating high performance protocol stacks. - * - * PJLIB is released under LGPL terms. - * - * @section download_sec Download - * - * PJLIB and all documentation can be downloaded from - * http://www.bulukucing.org. - * - * - * @section how_to_use_sec About This Documentation - * - * This document is generated directly from PJLIB source file using - * \a doxygen (http://www.doxygen.org). Doxygen is a great (and free!) - * tools for generating such documentation. - * - * @subsection doc_ver_subsec Version - * - * This document corresponds to PJLIB version 0.3-pre2. - * - * - * @subsection find_samples_subsec How to Read This Document - * - * This documentation is laid out more to be a reference guide instead - * of tutorial, therefore first time users may find it difficult to - * grasp PJLIB by reading this document alone. - * - * However, we've tried our best to make this document easy to follow. - * For first time users, we would suggest that you follow these steps - * when reading this documentation: - * - * - continue reading this introduction chapter. At the end of this - * chapter, you'll find section called \ref pjlib_fundamentals_sec - * which should guide you to understand basic things about PJLIB. - * - * - find information about specific features that you want to use - * in PJLIB. Use the Module Index to find out about all - * features in PJLIB (if you're browsing the HTML documentation, - * click on the \a Module link on top of the page, or if you're - * reading the PDF documentation, click on \a Module \a Documentation - * on the navigation pane on the left). - * - * @subsection doc_organize_sec How To's - * - * Please find below links to specific tasks that you probably - * want to do: - * - * - How to Build PJLIB - *\n - * Please refer to \ref pjlib_build_sys_pg page for more information. - * - * - How to Use PJLIB in My Application - *\n - * Please refer to \ref configure_app_sec for more information. - * - * - How to Port PJLIB - *\n - * Please refer to \ref porting_pjlib_pg page. - * - * - Where to Read Samples Documentation - *\n - * Most of the modules provide link to the corresponding sample file. - * Alternatively, to get the list of all examples, you can click on - * Related Pages on the top of HTML document or on - * PJLIB Page Documentation on navigation pane of your PDF reader. - * - * - * - * - * - * @section features_sec Features - * - * @subsection open_source_feat It's Open Source! - * - * PJLIB is currently released on LGPL license. We may release PJLIB under - * additional schemes in the future (such as GPL or MPL) to incorporate - * linking with specific application, however, one thing for sure is - * we will NEVER be able to make PJLIB a proprietary software. - * - * @subsection extreme_portable_feat Extreme Portability - * - * PJLIB is designed to be extremely portable. It can run on any kind - * of processors (16-bit, 32-bit, or 64-bit, big or little endian, single - * or multi-processors) and operating systems. Floating point or no - * floating point. Multi-threading or not. - * It can even run in environment where no ANSI LIBC is available. - * - * Currently PJLIB is being ported to: - * - x86, Win32 (Win95/98/ME, NT/2000/XP/2003, mingw). - * - x86, Linux (user mode and as kernel module(!)). - * - alpha, Linux - * And coming up: - * - x86, eCos - * - ultra-II, Solaris. - * - powerpc, MacOS - * - m68k, PalmOS. - * - arm, PocketPC - * - * No other library is known to have this extreme portability! - * - * @subsection small_size_feat Small in Size - * - * One of the primary objectives is to have library that is small in size for - * typical embedded applications. As a rough guidance, we aim to keep the - * library size below 100KB for it to be considered as small. - * As the result, most of the functionalities in the library can be tailored - * to meet the requirements; user can enable/disable specific functionalities - * to get the desired size/performance/functionality balance. - * - * For more info, please see @ref pj_config. - * - * @subsection no_dyn_mem No Dynamic Memory Allocations - * - * The central idea of PJLIB is that for applications to run as fast as it can, - * it should not use \a malloc() at all, but instead should get the memory - * from a preallocated storage pool. There are few things that can be - * optimized with this approach: - * - * - \a alloc() is a O(1) operation. - * - no mutex is used inside alloc(). It is assumed that synchronization - * will be used in higher abstraction by application anyway. - * - no \a free() is required. All chunks will be deleted when the pool is - * destroyed. - * - * The performance gained on some systems can be as high as 10x speed up - * against \a malloc() and \a free(). - * - * For more information, see \ref PJ_POOL_GROUP - * - * - * @subsection os_abstract_feat Operating System Abstraction - * - * PJLIB has abstractions for features that are normally not portable - * across operating systems: - * - @ref PJ_THREAD - *\n - * Portable thread manipulation. - * - @ref PJ_TLS - *\n - * Storing data in thread's private data. - * - @ref PJ_MUTEX - *\n - * Mutual exclusion protection. - * - @ref PJ_SEM - *\n - * Semaphores. - * - @ref PJ_ATOMIC - *\n - * Atomic variables and their operations. - * - @ref PJ_CRIT_SEC - *\n - * Fast locking of critical sections. - * - @ref PJ_LOCK - *\n - * High level abstraction for lock objects. - * - @ref PJ_EVENT - *\n - * Event object. - * - @ref PJ_TIME - *\n - * Portable time manipulation. - * - @ref PJ_TIMESTAMP - *\n - * High resolution time value. - * - etc. - * - * - * @subsection ll_network_io_sec Low-Level Network I/O - * - * PJLIB has very portable abstraction and fairly complete set of API for - * doing network I/O communications. At the lowest level, PJLIB provides: - * - * - @ref PJ_SOCK - *\n - * A highly portable socket abstraction, runs on all kind of - * network APIs such as standard BSD socket, Windows socket, Linux - * \b kernel socket, PalmOS networking API, etc. - * - * - @ref pj_addr_resolve - *\n - * Portable address resolution, which implements #pj_gethostbyname(). - * - * - @ref PJ_SOCK_SELECT - *\n - * A portable \a select() like API (#pj_sock_select()) which can be - * implemented with various back-end. - * - * - * @subsection hl_network_io_sec High-Level Network I/O - * - * At higher abstraction, PJLIB provides @ref PJ_IOQUEUE, - * which promotes creating high performance network - * applications by managing asynchronous I/O. This is a passive framework - * that utilizes the most effective way to manage asynchronous I/O - * on a given platform, such as: - * - IoCompletionPort on WinNT, - * - on Linux it can use either /dev/epoll or aio. - * - or to fall back to use @a select() - * - * At even a higher abstraction, PJLIB provides @ref PJ_EQUEUE, which - * combines asynchronous I/O with timer management and thread management - * to fasilitate creating trully high performance, event driven - * application. - * - * - * @subsection timer_mgmt_sec Timer Management - * - * A passive framework for managing timer, see @ref PJ_TIMER for more info. - * There is also function to retrieve high resolution timestamp - * from the system (see @ref PJ_TIMESTAMP). - * - * - * @subsection lexical_scanner_sec Lexical Scanner - * - * A fast, small, top-down lexical scanner to create fully optimized - * hand-written parser. See @ref PJ_SCAN for more info. - * - * @subsection data_struct_sec Various Data Structures - * - * Various data structures are provided in the library: - * - * - @ref PJ_PSTR - * - @ref PJ_ARRAY - * - @ref PJ_HASH - * - @ref PJ_LIST - * - @ref PJ_RBTREE - * - * - * @subsection exception_sec Exception Construct - * - * A convenient TRY/CATCH like construct to propagate errors, which by - * default are used by the @ref PJ_POOL_GROUP "memory pool" and - * the @ref PJ_SCAN "scanner". The exception - * construct can be used to write programs like below: - * - *
- *    #define SYNTAX_ERROR  1
- *
- *    PJ_TRY {
- *       msg = NULL;
- *       msg = parse_msg(buf, len);
- *    }
- *    PJ_CATCH ( SYNTAX_ERROR ) {
- *       .. handle error ..
- *    }
- *    PJ_END;
- * 
- * - * Please see @ref PJ_EXCEPT for more information. - * - * - * @subsection logging_sec Logging Facility - * - * PJLIB @ref PJ_LOG consists of macros to write logging information to - * some output device. Some of the features of the logging facility: - * - * - the verbosity can be fine-tuned both at compile time (to control - * the library size) or run-time (to control the verbosity of the - * information). - * - output device is configurable (e.g. stdout, printk, file, etc.) - * - log decoration is configurable. - * - * See @ref PJ_LOG for more information. - * - * - * @subsection guid_gen_sec Random and GUID Generation - * - * PJLIB provides facility to create random string - * (#pj_create_random_string()) or globally unique identifier - * (see @ref PJ_GUID). - * - * - * - * @section configure_app_sec Configuring Application to use PJLIB - * - * @subsection pjlib_compil_sec Building PJLIB - * - * Follow the instructions in \ref pjlib_build_sys_pg to build - * PJLIB. - * - * @subsection pjlib_compil_app_sec Building Applications with PJLIB - * - * Use the following settings when building applications with PJLIB. - * - * @subsubsection compil_inc_dir_sec Include Search Path - * - * Add this to your include search path ($PJLIB is PJLIB root directory): - *
- *   $PJLIB/include
- * 
- * - * @subsubsection compil_inc_file_sec Include PJLIB Header - * - * To include all PJLIB headers: - * \verbatim - #include - \endverbatim - * - * Alternatively, you can include individual PJLIB headers like this: - * \verbatim - #include - #include - \endverbatim - * - * - * @subsubsection compil_lib_dir_sec Library Path - * - * Add this to your library search path: - *
- *   $PJLIB/lib
- * 
- * - * Then add the appropriate PJLIB library to your link specification. For - * example, you would add \c libpj-i386-linux-gcc.a when you're building - * applications in Linux. - * - * - * @subsection pjlib_fundamentals_sec Principles in Using PJLIB - * - * Few things that you \b MUST do when using PJLIB, to make sure that - * you create trully portable applications. - * - * @subsubsection call_pjlib_init_sec Call pj_init() - * - * Before you do anything else, call \c pj_init(). This would make sure that - * PJLIB system is properly set up. - * - * @subsubsection no_ansi_subsec Do NOT Use ANSI C - * - * Contrary to popular teaching, ANSI C (and LIBC) is not the most portable - * library in the world, nor it's the most ubiquitous. For example, LIBC - * is not available in Linux kernel. Also normally LIBC will be excluded - * from compilation of RTOSes to reduce size. - * - * So for maximum portability, do NOT use ANSI C. Do not even try to include - * any other header files outside . Stick with the functionalities - * provided by PJLIB. - * - * - * @subsubsection string_rep_subsubsec Use pj_str_t instead of C Strings - * - * PJLIB uses pj_str_t instead of normal C strings. You SHOULD follow this - * convention too. Remember, ANSI string-h is not always available. And - * PJLIB string is faster! - * - * @subsubsection mem_alloc_subsubsec Use Pool for Memory Allocations - * - * You MUST NOT use \a malloc() or any other memory allocation functions. - * Use PJLIB pool instead! It's faster and most portable. - * - * @subsection logging_subsubsec Use Logging for Text Display - * - * DO NOT use for text output. Use PJLIB logging instead. - * - * - * @section porting_pjlib_sec0 Porting PJLIB - * - * Please see \ref porting_pjlib_pg page on more information to port - * PJLIB to new target. - * - * @section enjoy_sec Enjoy Using PJLIB! - * - * We hope that you find PJLIB usefull for your application. If you - * have any questions, suggestions, critics, bug fixes, or anything - * else, we would be happy to hear it. - * - * Enjoy using PJLIB! - * - * Benny Prijono < bennylp at bulukucing dot org > - */ - - - - -/*////////////////////////////////////////////////////////////////////////// */ -/* - BUILDING AND INSTALLING PJLIB - */ - - - -/** - * @page pjlib_build_sys_pg Building, and Installing PJLIB - * - * @section build_sys_install_sec Build and Installation - * - * @subsection build_sys_install_win32_sec Visual Studio - * - * The PJLIB Visual Studio workspace supports the building of PJLIB - * for Win32 target. Although currently only the Visual Studio 6 Workspace is - * actively maintained, developers with later version of Visual Studio - * can easily imports VS6 workspace into their IDE. - * - * To start building PJLIB projects with Visual Studio 6 or later, open - * the \a workspace file in the corresponding \b \c build directory. You have - * several choices on which \a dsw file to open: - \verbatim - $PJPROJECT/build/pjproject.dsw - $PJPROJECT/pjlib/build/pjlib.dsw - $PJPROJECT/pjsip/build/pjsip.dsw - ..etc - \endverbatim - * - * The easiest way is to open pjproject.dsw file in \b \c $PJPROJECT/build - * directory. However this will only build the required projects, not - * the complete projects. For example, the PJLIB test and samples projects - * are not included in this workspace. To build the complete projects, you must - * open and build each \a dsw file in \c build directory in each - * subprojects. For example, to open the complete PJLIB workspace, open - * pjlib.dsw in $PJPROJECT/pjlib/build directory. - * - * @subsection build_sys_install_unix_sec Make System - * - * For other targets, PJLIB provides a rather comprehensive build system - * that uses GNU \a make (and only GNU \a make will work). - * Currently, the build system supports building * PJLIB for these targets: - * - i386/Win32/mingw - * - i386/Linux - * - i386/Linux (kernel) - * - * Generally, steps required to build the projects are: - * - \verbatim - $ cd /home/user/pjproject-0.3 # <-- go to $PJPROJECT\n - $ vi build.mak # <-- set build target etc\n - $ cd pjlib/build # <-- go to projet's build dir\n - $ make # <-- build the project\n - \endverbatim - * - * For other project, \a cd to build directory in the project - * and execute \a make from there. - * - * \note For Linux kernel target, there are additional steps required, which - * will be explained in section \ref linux_kern_target_subsec. - * - * @subsubsection build_mak_sec Editing build.mak - * - * The \c build.mak file in \c $PJPROJECT root directory is used to - * specify the build configuration. This file is expected to export - * the following \a make variables: - * - * - \c MACHINE_NAME - *\n - * Target machine/processor, one of: { i386 }. - * - * - \c OS_NAME - *\n - * Target operating system, one of: { win32 | linux | linux-kernel }. - * - * - \c CC_NAME - *\n - * Compiler name: { gcc | vc } - * - * - \c HOST_NAME - *\n - * Build host: { unix | mingw } - * - * These variables will cause the correct configuration file in - * \c $PJPROJECT/build directory to be executed by \a make. For - * example, specifying \c OS_NAME=linux will cause file \c os-linux.mak - * in \c build directory to be executed. These files contain specific - * configuration for the option that is selected. - * - * For Linux kernel target, you are also required to declare the following - * variables in this file: - * - \c KERNEL_DIR: full path of kernel source tree. - * - \c KERNEL_ARCH: kernel ARCH options (e.g. "ARCH=um"), or leave blank - * for default. - * - \c PJPROJECT_DIR: full path of PJPROJECT source tree. - * - * Apart from these, there are also additional steps required to build - * Linux kernel target, which will be explained in \ref linux_kern_target_subsec. - * - * @subsubsection build_dir_sec Files in "build" Directory - * - * The *.mak files in \c $PJPROJECT/build directory are used to specify - * the configuration for the specified compiler, target machine target - * operating system, and host options. These files will be executed - * (included) by \a make during building process, depending on the values - * specified in $PJPROJECT/build.mak file. - * - * Normally you don't need to edit these files, except when you're porting - * PJLIB to new target. - * - * Below are the description of some files in this directory: - * - * - rules.mak: contains generic rules always included during make. - * - cc-gcc.mak: rules when gcc is used for compiler. - * - cc-vc.mak: rules when MSVC compiler is used. - * - host-mingw.mak: rules for building in mingw host. - * - host-unix.mak: rules for building in Unix/Posix host. - * - host-win32.mak: rules for building in Win32 command console - * (only valid when VC is used). - * - m-i386.mak: rules when target machine is an i386 processor. - * - m-m68k.mak: rules when target machine is an m68k processor. - * - os-linux.mak: rules when target OS is Linux. - * - os-linux-kernel.mak: rules when PJLIB is to be build as - * part of Linux kernel. - * - os-win32.mak: rules when target OS is Win32. - * - * @subsubsection invoking_make_sec Invoking make - * - * Normally, \a make is invoked in \c build directory under each project. - * For example, to build PJLIB, you would invoke \a make in - * \c $PJPROJECT/pjlib/build directory like below: - * - \verbatim - $ cd pjlib/build - $ make - \endverbatim - * - * - * - * @subsubsection linux_kern_target_subsec Linux Kernel Target - * - * \note - * BUILDING APPLICATIONS IN LINUX KERNEL MODE IS A VERY DANGEROUS BUSINESS. - * YOU MAY CRASH THE WHOLE OF YOUR SYSTEM, CORRUPT YOUR HARDISK, ETC. PJLIB - * KERNEL MODULES ARE STILL IN EXPERIMENTAL PHASE. DO NOT RUN IT IN PRODUCTION - * SYSTEMS OR OTHER SYSTEMS WHERE RISK OF LOSS OF DATA IS NOT ACCEPTABLE. - * YOU HAVE BEEN WARNED. - * - * \note - * User Mode Linux (UML) provides excellent way to experiment with Linux - * kernel without risking the stability of the host system. See - * http://user-mode-linux.sourceforge.net for details. - * - * \note - * I only use UML to experiment with PJLIB kernel modules. - * I wouldn't be so foolish to use my host Linux machine to experiment - * with this. - * - * \note - * You have been warned. - * - * For building PJLIB for Linux kernel target, there are additional steps required. - * In general, the additional tasks are: - * - Declare some more variables in build.mak file (this - * has been explained in \ref build_mak_sec above). - * - Perform these two small modifications in kernel source tree. - * - * There are two small modification need to be applied to the kernel tree. - * - * 1. Edit Makefile in kernel root source tree. - * - * Add the following lines at the end of the Makefile in your - * $KERNEL_SRC dir: - \verbatim -script: - $(SCRIPT) - \endverbatim - * - * \note Remember to replace spaces with tab in the Makefile. - * - * The modification above is needed to capture kernel's \c $CFLAGS and - * \c $CFLAGS_MODULE which will be used for PJLIB's compilation. - * - * 2. Add Additional Exports. - * - * We need the kernel to export some more symbols for our use. So we declare - * the additional symbols to be exported in extra-exports.c file, and add - * a this file to be compiled into the kernel: - * - * - Copy the file extra-exports.c from pjlib/src/pj - * directory to $KERNEL_SRC/kernel/ directory. - * - Edit Makefile in that directory, and add this line - * somewhere after the declaration of that variable: - \verbatim -obj-y += extra-exports.o - \endverbatim - * - * To illustrate what have been done in your kernel source tree, below - * is screenshot of my kernel source tree _after_ the modification. - * - \verbatim -[root@vpc-linux linux-2.6.7]# pwd -/usr/src/linux-2.6.7 -[root@vpc-linux linux-2.6.7]# -[root@vpc-linux linux-2.6.7]# -[root@vpc-linux linux-2.6.7]# tail Makefile - -endif # skip-makefile - -FORCE: - -.PHONY: script - -script: - $(SCRIPT) - -[root@vpc-linux linux-2.6.7]# -[root@vpc-linux linux-2.6.7]# -[root@vpc-linux linux-2.6.7]# head kernel/extra-exports.c -#include -#include - -EXPORT_SYMBOL(sys_select); - -EXPORT_SYMBOL(sys_epoll_create); -EXPORT_SYMBOL(sys_epoll_ctl); -EXPORT_SYMBOL(sys_epoll_wait); - -EXPORT_SYMBOL(sys_socket); -[root@vpc-linux linux-2.6.7]# -[root@vpc-linux linux-2.6.7]# -[root@vpc-linux linux-2.6.7]# head -15 kernel/Makefile -# -# Makefile for the linux kernel. -# - -obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ - exit.o itimer.o time.o softirq.o resource.o \ - sysctl.o capability.o ptrace.o timer.o user.o \ - signal.o sys.o kmod.o workqueue.o pid.o \ - rcupdate.o intermodule.o extable.o params.o posix-timers.o \ - kthread.o - -obj-y += extra-exports.o - -obj-$(CONFIG_FUTEX) += futex.o -obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o -[root@vpc-linux linux-2.6.7]# - - \endverbatim - * - * Then you must rebuild the kernel. - * If you fail to do this, you won't be able to insmod pjlib. - * - * \note You will see a lots of warning messages during pjlib-test compilation. - * The warning messages complain about unresolved symbols which are defined - * in pjlib module. You can safely ignore these warnings. However, you can not - * ignore warnings about non-pjlib unresolved symbols. - * - * - * @subsection makefile_explained_sec Makefile Explained - * - * The \a Makefile for each project (e.g. PJLIB, PJSIP, etc) should be - * very similar in the contents. The Makefile is located under \c build - * directory in each project subdir. - * - * @subsubsection pjlib_makefile_subsec PJLIB Makefile. - * - * Below is PJLIB's Makefile: - * - * \include build/Makefile - * - * @subsubsection pjlib_os_makefile_subsec PJLIB os-linux.mak. - * - * Below is file os-linux.mak file in - * $PJPROJECT/pjlib/build directory, - * which is OS specific configuration file for Linux target that is specific - * for PJLIB project. For \b global OS specific configuration, please see - * $PJPROJECT/build/os-*.mak. - * - * \include build/os-linux.mak - * - */ - - -/*////////////////////////////////////////////////////////////////////////// */ -/* - PORTING PJLIB - */ - - - -/** - * @page porting_pjlib_pg Porting PJLIB - * - * - * @section new_arch_sec Porting to New CPU Architecture - * - * Below is step-by-step guide to add support for new CPU architecture. - * This sample is based on porting to Alpha architecture; however steps for - * porting to other CPU architectures should be pretty similar. - * - * Also note that in this example, the operating system used is Linux. - * Should you wish to add support for new operating system, then follow - * the next section \ref porting_os_sec. - * - * Step-by-step guide to port to new CPU architecture: - * - decide the name for the new architecture. In this case, we choose - * alpha. - * - edit file $PJPROJECT/build.mak, and add new section for - * the new target: - *
- *      #
- *      # Linux alpha, gcc
- *      #
- *      export MACHINE_NAME := alpha
- *      export OS_NAME := linux
- *      export CC_NAME := gcc
- *      export HOST_NAME := unix
- *    
- * - * - create a new file $PJPROJECT/build/m-alpha.mak. - * Alternatively create a copy from other file in this directory. - * The contents of this file will look something like: - *
- *      export M_CFLAGS := $(CC_DEF)PJ_M_ALPHA=1
- *      export M_CXXFLAGS :=
- *      export M_LDFLAGS :=
- *      export M_SOURCES :=
- *    
- * - create a new file $PJPROJECT/pjlib/include/pj/compat/m_alpha.h. - * Alternatively create a copy from other header file in this directory. - * The contents of this file will look something like: - *
- *      #define PJ_HAS_PENTIUM          0
- *      #define PJ_IS_LITTLE_ENDIAN     1
- *      #define PJ_IS_BIG_ENDIAN        0
- *    
- * - edit pjlib/include/pj/config.h. Add new processor - * configuration in this header file, like follows: - *
- *      ...
- *      #elif defined (PJ_M_ALPHA) && PJ_M_ALPHA != 0
- *      #   include 
- *      ...
- *    
- * - done. Build PJLIB with: - *
- *      $ cd $PJPROJECT/pjlib/build
- *      $ make dep
- *      $ make clean
- *      $ make
- *    
- * - * @section porting_os_sec Porting to New Operating System Target - * - * This section will try to give you rough guideline on how to - * port PJLIB to a new target. As a sample, we give the target a name tag, - * for example xos (for X OS). - * - * @subsection new_compat_os_h_file_sec Create New Compat Header File - * - * You'll need to create a new header file - * include/pj/compat/os_xos.h. You can copy as a - * template other header file and edit it accordingly. - * - * @subsection modify_config_h_file_sec Modify config.h - * - * Then modify file include/pj/config.h to include - * this file accordingly (e.g. when macro PJ_XOS is - * defined): - * - \verbatim - ... - #elif defined(PJ_XOS) - # include - #else - #... - \endverbatim - * - * @subsection new_target_mak_file_sec Create New Global Make Config File - * - * Then you'll need to create global configuration file that - * is specific for this OS, i.e. os-xos.mak in - * $PJPROJECT/build directory. - * - * At very minimum, the file will normally need to define - * PJ_XOS=1 in the \c CFLAGS section: - * - \verbatim -# -# $PJPROJECT/build/os-xos.mak: -# -export OS_CFLAGS := $(CC_DEF)PJ_XOS=1 -export OS_CXXFLAGS := -export OS_LDFLAGS := -export OS_SOURCES := - \endverbatim - * - * - * @subsection new_target_prj_mak_file_sec Create New Project's Make Config File - * - * Then you'll need to create xos-specific configuration file - * for PJLIB. This file is also named os-xos.mak, - * but its located in pjlib/build directory. - * This file will specify source files that are specific to - * this OS to be included in the build process. - * - * Below is a sample: - \verbatim -# -# pjlib/build/os-xos.mak: -# XOS specific configuration for PJLIB. -# -export PJLIB_OBJS += os_core_xos.o \ - os_error_unix.o \ - os_time_ansi.o -export TEST_OBJS += main.o -export TARGETS = pjlib pjlib-test - \endverbatim - * - * @subsection new_target_src_sec Create and Edit Source Files - * - * You'll normally need to create at least these files: - * - os_core_xos.c: core OS specific - * functionality. - * - os_timestamp_xos.c: how to get timestamp - * in this OS. - * - * Depending on how things are done in your OS, you may need - * to create these files: - * - os_error_*.c: how to manipulate - * OS error codes. Alternatively you may use existing - * os_error_unix.c if the OS has \c errno and - * \c strerror() function. - * - ioqueue_*.c: if the OS has specific method - * to perform asynchronous I/O. Alternatively you may - * use existing ioqueue_select.c if the OS supports - * \c select() function call. - * - sock_*.c: if the OS has specific method - * to perform socket communication. Alternatively you may - * use existing sock_bsd.c if the OS supports - * BSD socket API, and edit include/pj/compat/socket.h - * file accordingly. - * - * You will also need to check various files in - * include/pj/compat/*.h, to see if they're - * compatible with your OS. - * - * @subsection new_target_build_file_sec Build The Project - * - * After basic building blocks have been created for the OS, then - * the easiest way to see which parts need to be fixed is by building - * the project and see the error messages. - * - * @subsection new_target_edit_vs_new_file_sec Editing Existing Files vs Creating New File - * - * When you encounter compatibility errors in PJLIB during porting, - * you have three options on how to fix the error: - * - edit the existing *.c file, and give it #ifdef - * switch for the new OS, or - * - edit include/pj/compat/*.h instead, or - * - create a totally new file. - * - * Basicly there is no strict rule on which approach is the best - * to use, however the following guidelines may be used: - * - if the file is expected to be completely different than - * any existing file, then perhaps you should create a completely - * new file. For example, file os_core_xxx.c will - * normally be different for each OS flavour. - * - if the difference can be localized in include/compat - * header file, and existing #ifdef switch is there, - * then preferably you should edit this include/compat - * header file. - * - if the existing *.c file has #ifdef switch, - * then you may add another #elif switch there. This - * normally is used for behaviors that are not totally - * different on each platform. - * - other than that above, use your own judgement on whether - * to edit the file or create new file etc. - */ - -#endif /* __PJ_DOXYGEN_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/doxygen.h 5 10/29/05 10:27p Bennylp $ */ +#ifndef __PJ_DOXYGEN_H__ +#define __PJ_DOXYGEN_H__ + +/** + * @file doxygen.h + * @brief Doxygen's mainpage. + */ + +/*//////////////////////////////////////////////////////////////////////////*/ +/* + INTRODUCTION PAGE + */ + +/** + * @mainpage Welcome to PJLIB! + * + * @section intro_sec What is PJLIB + * + * PJLIB is a small foundation library written in C for making scalable + * applications. Because of its small footprint, it can be used in embedded + * applications (we hope so!), but yet the library is also aimed for + * facilitating high performance protocol stacks. + * + * PJLIB is released under LGPL terms. + * + * @section download_sec Download + * + * PJLIB and all documentation can be downloaded from + * http://www.bulukucing.org. + * + * + * @section how_to_use_sec About This Documentation + * + * This document is generated directly from PJLIB source file using + * \a doxygen (http://www.doxygen.org). Doxygen is a great (and free!) + * tools for generating such documentation. + * + * @subsection doc_ver_subsec Version + * + * This document corresponds to PJLIB version 0.3-pre2. + * + * + * @subsection find_samples_subsec How to Read This Document + * + * This documentation is laid out more to be a reference guide instead + * of tutorial, therefore first time users may find it difficult to + * grasp PJLIB by reading this document alone. + * + * However, we've tried our best to make this document easy to follow. + * For first time users, we would suggest that you follow these steps + * when reading this documentation: + * + * - continue reading this introduction chapter. At the end of this + * chapter, you'll find section called \ref pjlib_fundamentals_sec + * which should guide you to understand basic things about PJLIB. + * + * - find information about specific features that you want to use + * in PJLIB. Use the Module Index to find out about all + * features in PJLIB (if you're browsing the HTML documentation, + * click on the \a Module link on top of the page, or if you're + * reading the PDF documentation, click on \a Module \a Documentation + * on the navigation pane on the left). + * + * @subsection doc_organize_sec How To's + * + * Please find below links to specific tasks that you probably + * want to do: + * + * - How to Build PJLIB + *\n + * Please refer to \ref pjlib_build_sys_pg page for more information. + * + * - How to Use PJLIB in My Application + *\n + * Please refer to \ref configure_app_sec for more information. + * + * - How to Port PJLIB + *\n + * Please refer to \ref porting_pjlib_pg page. + * + * - Where to Read Samples Documentation + *\n + * Most of the modules provide link to the corresponding sample file. + * Alternatively, to get the list of all examples, you can click on + * Related Pages on the top of HTML document or on + * PJLIB Page Documentation on navigation pane of your PDF reader. + * + * + * + * + * + * @section features_sec Features + * + * @subsection open_source_feat It's Open Source! + * + * PJLIB is currently released on LGPL license. We may release PJLIB under + * additional schemes in the future (such as GPL or MPL) to incorporate + * linking with specific application, however, one thing for sure is + * we will NEVER be able to make PJLIB a proprietary software. + * + * @subsection extreme_portable_feat Extreme Portability + * + * PJLIB is designed to be extremely portable. It can run on any kind + * of processors (16-bit, 32-bit, or 64-bit, big or little endian, single + * or multi-processors) and operating systems. Floating point or no + * floating point. Multi-threading or not. + * It can even run in environment where no ANSI LIBC is available. + * + * Currently PJLIB is being ported to: + * - x86, Win32 (Win95/98/ME, NT/2000/XP/2003, mingw). + * - x86, Linux (user mode and as kernel module(!)). + * - alpha, Linux + * And coming up: + * - x86, eCos + * - ultra-II, Solaris. + * - powerpc, MacOS + * - m68k, PalmOS. + * - arm, PocketPC + * + * No other library is known to have this extreme portability! + * + * @subsection small_size_feat Small in Size + * + * One of the primary objectives is to have library that is small in size for + * typical embedded applications. As a rough guidance, we aim to keep the + * library size below 100KB for it to be considered as small. + * As the result, most of the functionalities in the library can be tailored + * to meet the requirements; user can enable/disable specific functionalities + * to get the desired size/performance/functionality balance. + * + * For more info, please see @ref pj_config. + * + * @subsection no_dyn_mem No Dynamic Memory Allocations + * + * The central idea of PJLIB is that for applications to run as fast as it can, + * it should not use \a malloc() at all, but instead should get the memory + * from a preallocated storage pool. There are few things that can be + * optimized with this approach: + * + * - \a alloc() is a O(1) operation. + * - no mutex is used inside alloc(). It is assumed that synchronization + * will be used in higher abstraction by application anyway. + * - no \a free() is required. All chunks will be deleted when the pool is + * destroyed. + * + * The performance gained on some systems can be as high as 10x speed up + * against \a malloc() and \a free(). + * + * For more information, see \ref PJ_POOL_GROUP + * + * + * @subsection os_abstract_feat Operating System Abstraction + * + * PJLIB has abstractions for features that are normally not portable + * across operating systems: + * - @ref PJ_THREAD + *\n + * Portable thread manipulation. + * - @ref PJ_TLS + *\n + * Storing data in thread's private data. + * - @ref PJ_MUTEX + *\n + * Mutual exclusion protection. + * - @ref PJ_SEM + *\n + * Semaphores. + * - @ref PJ_ATOMIC + *\n + * Atomic variables and their operations. + * - @ref PJ_CRIT_SEC + *\n + * Fast locking of critical sections. + * - @ref PJ_LOCK + *\n + * High level abstraction for lock objects. + * - @ref PJ_EVENT + *\n + * Event object. + * - @ref PJ_TIME + *\n + * Portable time manipulation. + * - @ref PJ_TIMESTAMP + *\n + * High resolution time value. + * - etc. + * + * + * @subsection ll_network_io_sec Low-Level Network I/O + * + * PJLIB has very portable abstraction and fairly complete set of API for + * doing network I/O communications. At the lowest level, PJLIB provides: + * + * - @ref PJ_SOCK + *\n + * A highly portable socket abstraction, runs on all kind of + * network APIs such as standard BSD socket, Windows socket, Linux + * \b kernel socket, PalmOS networking API, etc. + * + * - @ref pj_addr_resolve + *\n + * Portable address resolution, which implements #pj_gethostbyname(). + * + * - @ref PJ_SOCK_SELECT + *\n + * A portable \a select() like API (#pj_sock_select()) which can be + * implemented with various back-end. + * + * + * @subsection hl_network_io_sec High-Level Network I/O + * + * At higher abstraction, PJLIB provides @ref PJ_IOQUEUE, + * which promotes creating high performance network + * applications by managing asynchronous I/O. This is a passive framework + * that utilizes the most effective way to manage asynchronous I/O + * on a given platform, such as: + * - IoCompletionPort on WinNT, + * - on Linux it can use either /dev/epoll or aio. + * - or to fall back to use @a select() + * + * At even a higher abstraction, PJLIB provides @ref PJ_EQUEUE, which + * combines asynchronous I/O with timer management and thread management + * to fasilitate creating trully high performance, event driven + * application. + * + * + * @subsection timer_mgmt_sec Timer Management + * + * A passive framework for managing timer, see @ref PJ_TIMER for more info. + * There is also function to retrieve high resolution timestamp + * from the system (see @ref PJ_TIMESTAMP). + * + * + * @subsection lexical_scanner_sec Lexical Scanner + * + * A fast, small, top-down lexical scanner to create fully optimized + * hand-written parser. See @ref PJ_SCAN for more info. + * + * @subsection data_struct_sec Various Data Structures + * + * Various data structures are provided in the library: + * + * - @ref PJ_PSTR + * - @ref PJ_ARRAY + * - @ref PJ_HASH + * - @ref PJ_LIST + * - @ref PJ_RBTREE + * + * + * @subsection exception_sec Exception Construct + * + * A convenient TRY/CATCH like construct to propagate errors, which by + * default are used by the @ref PJ_POOL_GROUP "memory pool" and + * the @ref PJ_SCAN "scanner". The exception + * construct can be used to write programs like below: + * + *
+ *    #define SYNTAX_ERROR  1
+ *
+ *    PJ_TRY {
+ *       msg = NULL;
+ *       msg = parse_msg(buf, len);
+ *    }
+ *    PJ_CATCH ( SYNTAX_ERROR ) {
+ *       .. handle error ..
+ *    }
+ *    PJ_END;
+ * 
+ * + * Please see @ref PJ_EXCEPT for more information. + * + * + * @subsection logging_sec Logging Facility + * + * PJLIB @ref PJ_LOG consists of macros to write logging information to + * some output device. Some of the features of the logging facility: + * + * - the verbosity can be fine-tuned both at compile time (to control + * the library size) or run-time (to control the verbosity of the + * information). + * - output device is configurable (e.g. stdout, printk, file, etc.) + * - log decoration is configurable. + * + * See @ref PJ_LOG for more information. + * + * + * @subsection guid_gen_sec Random and GUID Generation + * + * PJLIB provides facility to create random string + * (#pj_create_random_string()) or globally unique identifier + * (see @ref PJ_GUID). + * + * + * + * @section configure_app_sec Configuring Application to use PJLIB + * + * @subsection pjlib_compil_sec Building PJLIB + * + * Follow the instructions in \ref pjlib_build_sys_pg to build + * PJLIB. + * + * @subsection pjlib_compil_app_sec Building Applications with PJLIB + * + * Use the following settings when building applications with PJLIB. + * + * @subsubsection compil_inc_dir_sec Include Search Path + * + * Add this to your include search path ($PJLIB is PJLIB root directory): + *
+ *   $PJLIB/include
+ * 
+ * + * @subsubsection compil_inc_file_sec Include PJLIB Header + * + * To include all PJLIB headers: + * \verbatim + #include + \endverbatim + * + * Alternatively, you can include individual PJLIB headers like this: + * \verbatim + #include + #include + \endverbatim + * + * + * @subsubsection compil_lib_dir_sec Library Path + * + * Add this to your library search path: + *
+ *   $PJLIB/lib
+ * 
+ * + * Then add the appropriate PJLIB library to your link specification. For + * example, you would add \c libpj-i386-linux-gcc.a when you're building + * applications in Linux. + * + * + * @subsection pjlib_fundamentals_sec Principles in Using PJLIB + * + * Few things that you \b MUST do when using PJLIB, to make sure that + * you create trully portable applications. + * + * @subsubsection call_pjlib_init_sec Call pj_init() + * + * Before you do anything else, call \c pj_init(). This would make sure that + * PJLIB system is properly set up. + * + * @subsubsection no_ansi_subsec Do NOT Use ANSI C + * + * Contrary to popular teaching, ANSI C (and LIBC) is not the most portable + * library in the world, nor it's the most ubiquitous. For example, LIBC + * is not available in Linux kernel. Also normally LIBC will be excluded + * from compilation of RTOSes to reduce size. + * + * So for maximum portability, do NOT use ANSI C. Do not even try to include + * any other header files outside . Stick with the functionalities + * provided by PJLIB. + * + * + * @subsubsection string_rep_subsubsec Use pj_str_t instead of C Strings + * + * PJLIB uses pj_str_t instead of normal C strings. You SHOULD follow this + * convention too. Remember, ANSI string-h is not always available. And + * PJLIB string is faster! + * + * @subsubsection mem_alloc_subsubsec Use Pool for Memory Allocations + * + * You MUST NOT use \a malloc() or any other memory allocation functions. + * Use PJLIB pool instead! It's faster and most portable. + * + * @subsection logging_subsubsec Use Logging for Text Display + * + * DO NOT use for text output. Use PJLIB logging instead. + * + * + * @section porting_pjlib_sec0 Porting PJLIB + * + * Please see \ref porting_pjlib_pg page on more information to port + * PJLIB to new target. + * + * @section enjoy_sec Enjoy Using PJLIB! + * + * We hope that you find PJLIB usefull for your application. If you + * have any questions, suggestions, critics, bug fixes, or anything + * else, we would be happy to hear it. + * + * Enjoy using PJLIB! + * + * Benny Prijono < bennylp at bulukucing dot org > + */ + + + + +/*////////////////////////////////////////////////////////////////////////// */ +/* + BUILDING AND INSTALLING PJLIB + */ + + + +/** + * @page pjlib_build_sys_pg Building, and Installing PJLIB + * + * @section build_sys_install_sec Build and Installation + * + * @subsection build_sys_install_win32_sec Visual Studio + * + * The PJLIB Visual Studio workspace supports the building of PJLIB + * for Win32 target. Although currently only the Visual Studio 6 Workspace is + * actively maintained, developers with later version of Visual Studio + * can easily imports VS6 workspace into their IDE. + * + * To start building PJLIB projects with Visual Studio 6 or later, open + * the \a workspace file in the corresponding \b \c build directory. You have + * several choices on which \a dsw file to open: + \verbatim + $PJPROJECT/build/pjproject.dsw + $PJPROJECT/pjlib/build/pjlib.dsw + $PJPROJECT/pjsip/build/pjsip.dsw + ..etc + \endverbatim + * + * The easiest way is to open pjproject.dsw file in \b \c $PJPROJECT/build + * directory. However this will only build the required projects, not + * the complete projects. For example, the PJLIB test and samples projects + * are not included in this workspace. To build the complete projects, you must + * open and build each \a dsw file in \c build directory in each + * subprojects. For example, to open the complete PJLIB workspace, open + * pjlib.dsw in $PJPROJECT/pjlib/build directory. + * + * @subsection build_sys_install_unix_sec Make System + * + * For other targets, PJLIB provides a rather comprehensive build system + * that uses GNU \a make (and only GNU \a make will work). + * Currently, the build system supports building * PJLIB for these targets: + * - i386/Win32/mingw + * - i386/Linux + * - i386/Linux (kernel) + * + * Generally, steps required to build the projects are: + * + \verbatim + $ cd /home/user/pjproject-0.3 # <-- go to $PJPROJECT\n + $ vi build.mak # <-- set build target etc\n + $ cd pjlib/build # <-- go to projet's build dir\n + $ make # <-- build the project\n + \endverbatim + * + * For other project, \a cd to build directory in the project + * and execute \a make from there. + * + * \note For Linux kernel target, there are additional steps required, which + * will be explained in section \ref linux_kern_target_subsec. + * + * @subsubsection build_mak_sec Editing build.mak + * + * The \c build.mak file in \c $PJPROJECT root directory is used to + * specify the build configuration. This file is expected to export + * the following \a make variables: + * + * - \c MACHINE_NAME + *\n + * Target machine/processor, one of: { i386 }. + * + * - \c OS_NAME + *\n + * Target operating system, one of: { win32 | linux | linux-kernel }. + * + * - \c CC_NAME + *\n + * Compiler name: { gcc | vc } + * + * - \c HOST_NAME + *\n + * Build host: { unix | mingw } + * + * These variables will cause the correct configuration file in + * \c $PJPROJECT/build directory to be executed by \a make. For + * example, specifying \c OS_NAME=linux will cause file \c os-linux.mak + * in \c build directory to be executed. These files contain specific + * configuration for the option that is selected. + * + * For Linux kernel target, you are also required to declare the following + * variables in this file: + * - \c KERNEL_DIR: full path of kernel source tree. + * - \c KERNEL_ARCH: kernel ARCH options (e.g. "ARCH=um"), or leave blank + * for default. + * - \c PJPROJECT_DIR: full path of PJPROJECT source tree. + * + * Apart from these, there are also additional steps required to build + * Linux kernel target, which will be explained in \ref linux_kern_target_subsec. + * + * @subsubsection build_dir_sec Files in "build" Directory + * + * The *.mak files in \c $PJPROJECT/build directory are used to specify + * the configuration for the specified compiler, target machine target + * operating system, and host options. These files will be executed + * (included) by \a make during building process, depending on the values + * specified in $PJPROJECT/build.mak file. + * + * Normally you don't need to edit these files, except when you're porting + * PJLIB to new target. + * + * Below are the description of some files in this directory: + * + * - rules.mak: contains generic rules always included during make. + * - cc-gcc.mak: rules when gcc is used for compiler. + * - cc-vc.mak: rules when MSVC compiler is used. + * - host-mingw.mak: rules for building in mingw host. + * - host-unix.mak: rules for building in Unix/Posix host. + * - host-win32.mak: rules for building in Win32 command console + * (only valid when VC is used). + * - m-i386.mak: rules when target machine is an i386 processor. + * - m-m68k.mak: rules when target machine is an m68k processor. + * - os-linux.mak: rules when target OS is Linux. + * - os-linux-kernel.mak: rules when PJLIB is to be build as + * part of Linux kernel. + * - os-win32.mak: rules when target OS is Win32. + * + * @subsubsection invoking_make_sec Invoking make + * + * Normally, \a make is invoked in \c build directory under each project. + * For example, to build PJLIB, you would invoke \a make in + * \c $PJPROJECT/pjlib/build directory like below: + * + \verbatim + $ cd pjlib/build + $ make + \endverbatim + * + * + * + * @subsubsection linux_kern_target_subsec Linux Kernel Target + * + * \note + * BUILDING APPLICATIONS IN LINUX KERNEL MODE IS A VERY DANGEROUS BUSINESS. + * YOU MAY CRASH THE WHOLE OF YOUR SYSTEM, CORRUPT YOUR HARDISK, ETC. PJLIB + * KERNEL MODULES ARE STILL IN EXPERIMENTAL PHASE. DO NOT RUN IT IN PRODUCTION + * SYSTEMS OR OTHER SYSTEMS WHERE RISK OF LOSS OF DATA IS NOT ACCEPTABLE. + * YOU HAVE BEEN WARNED. + * + * \note + * User Mode Linux (UML) provides excellent way to experiment with Linux + * kernel without risking the stability of the host system. See + * http://user-mode-linux.sourceforge.net for details. + * + * \note + * I only use UML to experiment with PJLIB kernel modules. + * I wouldn't be so foolish to use my host Linux machine to experiment + * with this. + * + * \note + * You have been warned. + * + * For building PJLIB for Linux kernel target, there are additional steps required. + * In general, the additional tasks are: + * - Declare some more variables in build.mak file (this + * has been explained in \ref build_mak_sec above). + * - Perform these two small modifications in kernel source tree. + * + * There are two small modification need to be applied to the kernel tree. + * + * 1. Edit Makefile in kernel root source tree. + * + * Add the following lines at the end of the Makefile in your + * $KERNEL_SRC dir: + \verbatim +script: + $(SCRIPT) + \endverbatim + * + * \note Remember to replace spaces with tab in the Makefile. + * + * The modification above is needed to capture kernel's \c $CFLAGS and + * \c $CFLAGS_MODULE which will be used for PJLIB's compilation. + * + * 2. Add Additional Exports. + * + * We need the kernel to export some more symbols for our use. So we declare + * the additional symbols to be exported in extra-exports.c file, and add + * a this file to be compiled into the kernel: + * + * - Copy the file extra-exports.c from pjlib/src/pj + * directory to $KERNEL_SRC/kernel/ directory. + * - Edit Makefile in that directory, and add this line + * somewhere after the declaration of that variable: + \verbatim +obj-y += extra-exports.o + \endverbatim + * + * To illustrate what have been done in your kernel source tree, below + * is screenshot of my kernel source tree _after_ the modification. + * + \verbatim +[root@vpc-linux linux-2.6.7]# pwd +/usr/src/linux-2.6.7 +[root@vpc-linux linux-2.6.7]# +[root@vpc-linux linux-2.6.7]# +[root@vpc-linux linux-2.6.7]# tail Makefile + +endif # skip-makefile + +FORCE: + +.PHONY: script + +script: + $(SCRIPT) + +[root@vpc-linux linux-2.6.7]# +[root@vpc-linux linux-2.6.7]# +[root@vpc-linux linux-2.6.7]# head kernel/extra-exports.c +#include +#include + +EXPORT_SYMBOL(sys_select); + +EXPORT_SYMBOL(sys_epoll_create); +EXPORT_SYMBOL(sys_epoll_ctl); +EXPORT_SYMBOL(sys_epoll_wait); + +EXPORT_SYMBOL(sys_socket); +[root@vpc-linux linux-2.6.7]# +[root@vpc-linux linux-2.6.7]# +[root@vpc-linux linux-2.6.7]# head -15 kernel/Makefile +# +# Makefile for the linux kernel. +# + +obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ + exit.o itimer.o time.o softirq.o resource.o \ + sysctl.o capability.o ptrace.o timer.o user.o \ + signal.o sys.o kmod.o workqueue.o pid.o \ + rcupdate.o intermodule.o extable.o params.o posix-timers.o \ + kthread.o + +obj-y += extra-exports.o + +obj-$(CONFIG_FUTEX) += futex.o +obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o +[root@vpc-linux linux-2.6.7]# + + \endverbatim + * + * Then you must rebuild the kernel. + * If you fail to do this, you won't be able to insmod pjlib. + * + * \note You will see a lots of warning messages during pjlib-test compilation. + * The warning messages complain about unresolved symbols which are defined + * in pjlib module. You can safely ignore these warnings. However, you can not + * ignore warnings about non-pjlib unresolved symbols. + * + * + * @subsection makefile_explained_sec Makefile Explained + * + * The \a Makefile for each project (e.g. PJLIB, PJSIP, etc) should be + * very similar in the contents. The Makefile is located under \c build + * directory in each project subdir. + * + * @subsubsection pjlib_makefile_subsec PJLIB Makefile. + * + * Below is PJLIB's Makefile: + * + * \include build/Makefile + * + * @subsubsection pjlib_os_makefile_subsec PJLIB os-linux.mak. + * + * Below is file os-linux.mak file in + * $PJPROJECT/pjlib/build directory, + * which is OS specific configuration file for Linux target that is specific + * for PJLIB project. For \b global OS specific configuration, please see + * $PJPROJECT/build/os-*.mak. + * + * \include build/os-linux.mak + * + */ + + +/*////////////////////////////////////////////////////////////////////////// */ +/* + PORTING PJLIB + */ + + + +/** + * @page porting_pjlib_pg Porting PJLIB + * + * + * @section new_arch_sec Porting to New CPU Architecture + * + * Below is step-by-step guide to add support for new CPU architecture. + * This sample is based on porting to Alpha architecture; however steps for + * porting to other CPU architectures should be pretty similar. + * + * Also note that in this example, the operating system used is Linux. + * Should you wish to add support for new operating system, then follow + * the next section \ref porting_os_sec. + * + * Step-by-step guide to port to new CPU architecture: + * - decide the name for the new architecture. In this case, we choose + * alpha. + * - edit file $PJPROJECT/build.mak, and add new section for + * the new target: + *
+ *      #
+ *      # Linux alpha, gcc
+ *      #
+ *      export MACHINE_NAME := alpha
+ *      export OS_NAME := linux
+ *      export CC_NAME := gcc
+ *      export HOST_NAME := unix
+ *    
+ * + * - create a new file $PJPROJECT/build/m-alpha.mak. + * Alternatively create a copy from other file in this directory. + * The contents of this file will look something like: + *
+ *      export M_CFLAGS := $(CC_DEF)PJ_M_ALPHA=1
+ *      export M_CXXFLAGS :=
+ *      export M_LDFLAGS :=
+ *      export M_SOURCES :=
+ *    
+ * - create a new file $PJPROJECT/pjlib/include/pj/compat/m_alpha.h. + * Alternatively create a copy from other header file in this directory. + * The contents of this file will look something like: + *
+ *      #define PJ_HAS_PENTIUM          0
+ *      #define PJ_IS_LITTLE_ENDIAN     1
+ *      #define PJ_IS_BIG_ENDIAN        0
+ *    
+ * - edit pjlib/include/pj/config.h. Add new processor + * configuration in this header file, like follows: + *
+ *      ...
+ *      #elif defined (PJ_M_ALPHA) && PJ_M_ALPHA != 0
+ *      #   include 
+ *      ...
+ *    
+ * - done. Build PJLIB with: + *
+ *      $ cd $PJPROJECT/pjlib/build
+ *      $ make dep
+ *      $ make clean
+ *      $ make
+ *    
+ * + * @section porting_os_sec Porting to New Operating System Target + * + * This section will try to give you rough guideline on how to + * port PJLIB to a new target. As a sample, we give the target a name tag, + * for example xos (for X OS). + * + * @subsection new_compat_os_h_file_sec Create New Compat Header File + * + * You'll need to create a new header file + * include/pj/compat/os_xos.h. You can copy as a + * template other header file and edit it accordingly. + * + * @subsection modify_config_h_file_sec Modify config.h + * + * Then modify file include/pj/config.h to include + * this file accordingly (e.g. when macro PJ_XOS is + * defined): + * + \verbatim + ... + #elif defined(PJ_XOS) + # include + #else + #... + \endverbatim + * + * @subsection new_target_mak_file_sec Create New Global Make Config File + * + * Then you'll need to create global configuration file that + * is specific for this OS, i.e. os-xos.mak in + * $PJPROJECT/build directory. + * + * At very minimum, the file will normally need to define + * PJ_XOS=1 in the \c CFLAGS section: + * + \verbatim +# +# $PJPROJECT/build/os-xos.mak: +# +export OS_CFLAGS := $(CC_DEF)PJ_XOS=1 +export OS_CXXFLAGS := +export OS_LDFLAGS := +export OS_SOURCES := + \endverbatim + * + * + * @subsection new_target_prj_mak_file_sec Create New Project's Make Config File + * + * Then you'll need to create xos-specific configuration file + * for PJLIB. This file is also named os-xos.mak, + * but its located in pjlib/build directory. + * This file will specify source files that are specific to + * this OS to be included in the build process. + * + * Below is a sample: + \verbatim +# +# pjlib/build/os-xos.mak: +# XOS specific configuration for PJLIB. +# +export PJLIB_OBJS += os_core_xos.o \ + os_error_unix.o \ + os_time_ansi.o +export TEST_OBJS += main.o +export TARGETS = pjlib pjlib-test + \endverbatim + * + * @subsection new_target_src_sec Create and Edit Source Files + * + * You'll normally need to create at least these files: + * - os_core_xos.c: core OS specific + * functionality. + * - os_timestamp_xos.c: how to get timestamp + * in this OS. + * + * Depending on how things are done in your OS, you may need + * to create these files: + * - os_error_*.c: how to manipulate + * OS error codes. Alternatively you may use existing + * os_error_unix.c if the OS has \c errno and + * \c strerror() function. + * - ioqueue_*.c: if the OS has specific method + * to perform asynchronous I/O. Alternatively you may + * use existing ioqueue_select.c if the OS supports + * \c select() function call. + * - sock_*.c: if the OS has specific method + * to perform socket communication. Alternatively you may + * use existing sock_bsd.c if the OS supports + * BSD socket API, and edit include/pj/compat/socket.h + * file accordingly. + * + * You will also need to check various files in + * include/pj/compat/*.h, to see if they're + * compatible with your OS. + * + * @subsection new_target_build_file_sec Build The Project + * + * After basic building blocks have been created for the OS, then + * the easiest way to see which parts need to be fixed is by building + * the project and see the error messages. + * + * @subsection new_target_edit_vs_new_file_sec Editing Existing Files vs Creating New File + * + * When you encounter compatibility errors in PJLIB during porting, + * you have three options on how to fix the error: + * - edit the existing *.c file, and give it #ifdef + * switch for the new OS, or + * - edit include/pj/compat/*.h instead, or + * - create a totally new file. + * + * Basicly there is no strict rule on which approach is the best + * to use, however the following guidelines may be used: + * - if the file is expected to be completely different than + * any existing file, then perhaps you should create a completely + * new file. For example, file os_core_xxx.c will + * normally be different for each OS flavour. + * - if the difference can be localized in include/compat + * header file, and existing #ifdef switch is there, + * then preferably you should edit this include/compat + * header file. + * - if the existing *.c file has #ifdef switch, + * then you may add another #elif switch there. This + * normally is used for behaviors that are not totally + * different on each platform. + * - other than that above, use your own judgement on whether + * to edit the file or create new file etc. + */ + +#endif /* __PJ_DOXYGEN_H__ */ + diff --git a/pjlib/include/pj/equeue.h b/pjlib/include/pj/equeue.h index 294304d0..1accad54 100644 --- a/pjlib/include/pj/equeue.h +++ b/pjlib/include/pj/equeue.h @@ -1,319 +1,319 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/equeue.h 2 10/14/05 12:26a Bennylp $ */ -#ifndef __PJ_EQUEUE_H__ -#define __PJ_EQUEUE_H__ - -/** - * @file equeue.h - * @brief Event Queue - */ -#include - - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_EQUEUE Event Queue - * @brief Event Queue - * @ingroup PJ_OS - * @{ - */ - - -/** - * Opaque data type for Event Queue. - */ -typedef struct pj_equeue_t pj_equeue_t; - -/** - * Opaque data type for Event Queue key. - */ -typedef struct pj_equeue_key_t pj_equeue_key_t; - - -/** - * This structure describes the callbacks to be called when I/O operation - * completes. - */ -typedef struct pj_io_callback -{ - /** - * This callback is called when #pj_equeue_read, #pj_equeue_recv or - * #pj_equeue_recvfrom completes. - * - * @param key The key. - * @param bytes_read The size of data that has just been read. - */ - void (*on_read_complete)(pj_equeue_key_t *key, pj_ssize_t bytes_read); - - /** - * This callback is called when #pj_equeue_write, #pj_equeue_send, or - * #pj_equeue_sendto completes. - * - * @param key The key. - * @param bytes_read The size of data that has just been written. - */ - void (*on_write_complete)(pj_equeue_key_t *key, pj_ssize_t bytes_sent); - - /** - * This callback is called when #pj_equeue_accept completes. - * - * @param key The key. - * @param status Zero if the operation completes successfully. - */ - void (*on_accept_complete)(pj_equeue_key_t *key, int status); - - /** - * This callback is called when #pj_equeue_connect completes. - * - * @param key The key. - * @param status Zero if the operation completes successfully. - */ - void (*on_connect_complete)(pj_equeue_key_t *key, int status); - -} pj_io_callback; - -/** - * Event Queue options. - */ -typedef struct pj_equeue_options -{ - /** Maximum number of threads that are allowed to access Event Queue - * simulteneously. - */ - unsigned nb_threads; - - /** If non-zero, then no mutex protection will be used. */ - pj_bool_t no_lock; - - /** Interval of the busy loop inside the event queue. - * The time resolution here determines the accuracy of the - * timer in the Event Queue. - */ - pj_time_val poll_interval; - -} pj_equeue_options; - - -/** - * Error value returned by I/O operations to indicate that the operation - * can't complete immediately and will complete later. - */ -#define PJ_EQUEUE_PENDING (-2) - -/** - * Types of Event Queue operation. - */ -typedef enum pj_equeue_op -{ - PJ_EQUEUE_OP_NONE = 0, /**< No operation. */ - PJ_EQUEUE_OP_READ = 1, /**< read() operation. */ - PJ_EQUEUE_OP_RECV_FROM = 2, /**< recvfrom() operation. */ - PJ_EQUEUE_OP_WRITE = 4, /**< write() operation. */ - PJ_EQUEUE_OP_SEND_TO = 8, /**< sendto() operation. */ -#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 - PJ_EQUEUE_OP_ACCEPT = 16, /**< accept() operation. */ - PJ_EQUEUE_OP_CONNECT = 32, /**< connect() operation. */ -#endif /* PJ_HAS_TCP */ -} pj_equeue_op; - - - -/** - * Initialize Event Queue options with default values. - * - * @param options Event Queue options. - */ -PJ_DECL(void) pj_equeue_options_init(pj_equeue_options *options); - -/** - * Create a new Event Queue framework. - * - * @param pool The pool to allocate the event queue structure. - * @param options Event queue options, or if NULL is given, then - * default options will be used. - * @param equeue Pointer to receive event queue structure. - * - * @return zero on success. - */ -PJ_DECL(pj_status_t) pj_equeue_create( pj_pool_t *pool, - const pj_equeue_options *options, - pj_equeue_t **equeue); - -/** - * Get the first instance of Event Queue, or NULL if no Event Queue - * instance has been created in the application. - * - * @return The first instance of Event Queue created, or NULL. - */ -PJ_DECL(pj_equeue_t*) pj_equeue_instance(void); - -/** - * Destroy the Event Queue. - * - * @param equeue The Event Queue instance to be destroyed. - */ -PJ_DECL(pj_status_t) pj_equeue_destroy( pj_equeue_t *equeue ); - -/** - * Customize the lock object that is used by the Event Queue. - * - * @param equeue The Event Queue instance. - * @param lock The lock object. - * @param auto_del If non-zero, the lock will be destroyed by - * Event Queue. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_equeue_set_lock( pj_equeue_t *equeue, - pj_lock_t *lock, - pj_bool_t auto_del); - -/** - * Associate an Event Queue key to particular handle. The key is also - * associated with the callback and user data, which will be used by - * the Event Queue framework when signalling event back to application. - * - * @param pool To allocate the resource for the specified handle, which - * must be valid until the handle/key is unregistered - * from Event Queue. - * @param equeue The Event Queue. - * @param hnd The OS handle to be registered, which can be a socket - * descriptor (pj_sock_t), file descriptor, etc. - * @param cb Callback to be called when I/O operation completes. - * @param user_data User data to be associated with the key. - * @param key Pointer to receive the key. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_equeue_register( pj_pool_t *pool, - pj_equeue_t *equeue, - pj_oshandle_t hnd, - pj_io_callback *cb, - void *user_data, - pj_equeue_key_t **key); - -/** - * Retrieve user data associated with a key. - * - * @param key The Event Queue key. - * - * @return User data associated with the key. - */ -PJ_DECL(void*) pj_equeue_get_user_data( pj_equeue_key_t *key ); - - -/** - * Unregister Event Queue key from the Event Queue. - * - * @param equeue The Event Queue. - * @param key The key. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_equeue_unregister( pj_equeue_t *equeue, - pj_equeue_key_t *key); - -/** - * Instruct the Event Queue to read from the specified handle. This function - * returns immediately (i.e. non-blocking) regardless whether some data has - * been transfered. If the operation can't complete immediately, caller will - * be notified about the completion when it calls pj_equeue_poll(). - * - * @param key The key that uniquely identifies the handle. - * @param buffer The buffer to hold the read data. The caller MUST make sure - * that this buffer remain valid until the framework completes - * reading the handle. - * @param size The maximum size to be read. - * - * @return - * - zero or positive number to indicate the number of bytes has been - * read, and in this case the operation was not queued. - * - (-1) on error, which in this case operation was not queued. - * - PJ_EQUEUE_PENDING if the operation has been queued. - */ -PJ_DECL(pj_ssize_t) pj_equeue_read( pj_equeue_key_t *key, - void *buffer, - pj_size_t size); - -/** - * Start recv() operation on the specified handle. - * - * @see ::pj_ioqueue_read - */ -PJ_DECL(pj_ssize_t) pj_equeue_recv( pj_equeue_key_t *key, - void *buf, - pj_size_t size, - unsigned flags); - -/** - * Start recvfrom() operation on the specified handle. - * - * @see ::pj_equeue_read - */ -PJ_DECL(pj_ssize_t) pj_equeue_recvfrom( pj_equeue_key_t *key, - void *buf, - pj_size_t size, - unsigned flags, - pj_sockaddr_t *addr, - int *addrlen ); - -/** - * Write. - */ -PJ_DECL(pj_ssize_t) pj_equeue_write( pj_equeue_key_t *key, - const void *buf, - pj_size_t size); - -/** - * Send. - */ -PJ_DECL(pj_ssize_t) pj_equeue_send( pj_equeue_key_t *key, - const void *buf, - pj_size_t size, - unsigned flags); - -/** - * Sendto. - */ -PJ_DECL(pj_ssize_t) pj_equeue_sendto( pj_equeue_key_t *key, - const void *buf, - pj_size_t size, - unsigned flags, - const pj_sockaddr_t *addr, - int addrlen); - -/** - * Schedule timer. - */ -PJ_DECL(pj_status_t) pj_equeue_schedule_timer( pj_equeue_t *equeue, - const pj_time_val *timeout, - pj_timer_entry *entry); - -/** - * Cancel timer. - */ -PJ_DECL(pj_status_t) pj_equeue_cancel_timer( pj_equeue_t *equeue, - pj_timer_entry *entry); - -/** - * Poll for events. - */ -PJ_DECL(pj_status_t) pj_equeue_poll( pj_equeue_t *equeue, - const pj_time_val *timeout ); - -/** - * Run. - */ -PJ_DECL(pj_status_t) pj_equeue_run( pj_equeue_t *equeue ); - -/** - * Stop all running threads. - */ -PJ_DECL(pj_status_t) pj_equeue_stop( pj_equeue_t *equeue ); - - -/** @} */ - -PJ_END_DECL - -#endif /* __PJ_EQUEUE_H__ */ +/* $Header: /pjproject-0.3/pjlib/include/pj/equeue.h 2 10/14/05 12:26a Bennylp $ */ +#ifndef __PJ_EQUEUE_H__ +#define __PJ_EQUEUE_H__ + +/** + * @file equeue.h + * @brief Event Queue + */ +#include + + +PJ_BEGIN_DECL + +/** + * @defgroup PJ_EQUEUE Event Queue + * @brief Event Queue + * @ingroup PJ_OS + * @{ + */ + + +/** + * Opaque data type for Event Queue. + */ +typedef struct pj_equeue_t pj_equeue_t; + +/** + * Opaque data type for Event Queue key. + */ +typedef struct pj_equeue_key_t pj_equeue_key_t; + + +/** + * This structure describes the callbacks to be called when I/O operation + * completes. + */ +typedef struct pj_io_callback +{ + /** + * This callback is called when #pj_equeue_read, #pj_equeue_recv or + * #pj_equeue_recvfrom completes. + * + * @param key The key. + * @param bytes_read The size of data that has just been read. + */ + void (*on_read_complete)(pj_equeue_key_t *key, pj_ssize_t bytes_read); + + /** + * This callback is called when #pj_equeue_write, #pj_equeue_send, or + * #pj_equeue_sendto completes. + * + * @param key The key. + * @param bytes_read The size of data that has just been written. + */ + void (*on_write_complete)(pj_equeue_key_t *key, pj_ssize_t bytes_sent); + + /** + * This callback is called when #pj_equeue_accept completes. + * + * @param key The key. + * @param status Zero if the operation completes successfully. + */ + void (*on_accept_complete)(pj_equeue_key_t *key, int status); + + /** + * This callback is called when #pj_equeue_connect completes. + * + * @param key The key. + * @param status Zero if the operation completes successfully. + */ + void (*on_connect_complete)(pj_equeue_key_t *key, int status); + +} pj_io_callback; + +/** + * Event Queue options. + */ +typedef struct pj_equeue_options +{ + /** Maximum number of threads that are allowed to access Event Queue + * simulteneously. + */ + unsigned nb_threads; + + /** If non-zero, then no mutex protection will be used. */ + pj_bool_t no_lock; + + /** Interval of the busy loop inside the event queue. + * The time resolution here determines the accuracy of the + * timer in the Event Queue. + */ + pj_time_val poll_interval; + +} pj_equeue_options; + + +/** + * Error value returned by I/O operations to indicate that the operation + * can't complete immediately and will complete later. + */ +#define PJ_EQUEUE_PENDING (-2) + +/** + * Types of Event Queue operation. + */ +typedef enum pj_equeue_op +{ + PJ_EQUEUE_OP_NONE = 0, /**< No operation. */ + PJ_EQUEUE_OP_READ = 1, /**< read() operation. */ + PJ_EQUEUE_OP_RECV_FROM = 2, /**< recvfrom() operation. */ + PJ_EQUEUE_OP_WRITE = 4, /**< write() operation. */ + PJ_EQUEUE_OP_SEND_TO = 8, /**< sendto() operation. */ +#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 + PJ_EQUEUE_OP_ACCEPT = 16, /**< accept() operation. */ + PJ_EQUEUE_OP_CONNECT = 32, /**< connect() operation. */ +#endif /* PJ_HAS_TCP */ +} pj_equeue_op; + + + +/** + * Initialize Event Queue options with default values. + * + * @param options Event Queue options. + */ +PJ_DECL(void) pj_equeue_options_init(pj_equeue_options *options); + +/** + * Create a new Event Queue framework. + * + * @param pool The pool to allocate the event queue structure. + * @param options Event queue options, or if NULL is given, then + * default options will be used. + * @param equeue Pointer to receive event queue structure. + * + * @return zero on success. + */ +PJ_DECL(pj_status_t) pj_equeue_create( pj_pool_t *pool, + const pj_equeue_options *options, + pj_equeue_t **equeue); + +/** + * Get the first instance of Event Queue, or NULL if no Event Queue + * instance has been created in the application. + * + * @return The first instance of Event Queue created, or NULL. + */ +PJ_DECL(pj_equeue_t*) pj_equeue_instance(void); + +/** + * Destroy the Event Queue. + * + * @param equeue The Event Queue instance to be destroyed. + */ +PJ_DECL(pj_status_t) pj_equeue_destroy( pj_equeue_t *equeue ); + +/** + * Customize the lock object that is used by the Event Queue. + * + * @param equeue The Event Queue instance. + * @param lock The lock object. + * @param auto_del If non-zero, the lock will be destroyed by + * Event Queue. + * + * @return Zero on success. + */ +PJ_DECL(pj_status_t) pj_equeue_set_lock( pj_equeue_t *equeue, + pj_lock_t *lock, + pj_bool_t auto_del); + +/** + * Associate an Event Queue key to particular handle. The key is also + * associated with the callback and user data, which will be used by + * the Event Queue framework when signalling event back to application. + * + * @param pool To allocate the resource for the specified handle, which + * must be valid until the handle/key is unregistered + * from Event Queue. + * @param equeue The Event Queue. + * @param hnd The OS handle to be registered, which can be a socket + * descriptor (pj_sock_t), file descriptor, etc. + * @param cb Callback to be called when I/O operation completes. + * @param user_data User data to be associated with the key. + * @param key Pointer to receive the key. + * + * @return Zero on success. + */ +PJ_DECL(pj_status_t) pj_equeue_register( pj_pool_t *pool, + pj_equeue_t *equeue, + pj_oshandle_t hnd, + pj_io_callback *cb, + void *user_data, + pj_equeue_key_t **key); + +/** + * Retrieve user data associated with a key. + * + * @param key The Event Queue key. + * + * @return User data associated with the key. + */ +PJ_DECL(void*) pj_equeue_get_user_data( pj_equeue_key_t *key ); + + +/** + * Unregister Event Queue key from the Event Queue. + * + * @param equeue The Event Queue. + * @param key The key. + * + * @return Zero on success. + */ +PJ_DECL(pj_status_t) pj_equeue_unregister( pj_equeue_t *equeue, + pj_equeue_key_t *key); + +/** + * Instruct the Event Queue to read from the specified handle. This function + * returns immediately (i.e. non-blocking) regardless whether some data has + * been transfered. If the operation can't complete immediately, caller will + * be notified about the completion when it calls pj_equeue_poll(). + * + * @param key The key that uniquely identifies the handle. + * @param buffer The buffer to hold the read data. The caller MUST make sure + * that this buffer remain valid until the framework completes + * reading the handle. + * @param size The maximum size to be read. + * + * @return + * - zero or positive number to indicate the number of bytes has been + * read, and in this case the operation was not queued. + * - (-1) on error, which in this case operation was not queued. + * - PJ_EQUEUE_PENDING if the operation has been queued. + */ +PJ_DECL(pj_ssize_t) pj_equeue_read( pj_equeue_key_t *key, + void *buffer, + pj_size_t size); + +/** + * Start recv() operation on the specified handle. + * + * @see ::pj_ioqueue_read + */ +PJ_DECL(pj_ssize_t) pj_equeue_recv( pj_equeue_key_t *key, + void *buf, + pj_size_t size, + unsigned flags); + +/** + * Start recvfrom() operation on the specified handle. + * + * @see ::pj_equeue_read + */ +PJ_DECL(pj_ssize_t) pj_equeue_recvfrom( pj_equeue_key_t *key, + void *buf, + pj_size_t size, + unsigned flags, + pj_sockaddr_t *addr, + int *addrlen ); + +/** + * Write. + */ +PJ_DECL(pj_ssize_t) pj_equeue_write( pj_equeue_key_t *key, + const void *buf, + pj_size_t size); + +/** + * Send. + */ +PJ_DECL(pj_ssize_t) pj_equeue_send( pj_equeue_key_t *key, + const void *buf, + pj_size_t size, + unsigned flags); + +/** + * Sendto. + */ +PJ_DECL(pj_ssize_t) pj_equeue_sendto( pj_equeue_key_t *key, + const void *buf, + pj_size_t size, + unsigned flags, + const pj_sockaddr_t *addr, + int addrlen); + +/** + * Schedule timer. + */ +PJ_DECL(pj_status_t) pj_equeue_schedule_timer( pj_equeue_t *equeue, + const pj_time_val *timeout, + pj_timer_entry *entry); + +/** + * Cancel timer. + */ +PJ_DECL(pj_status_t) pj_equeue_cancel_timer( pj_equeue_t *equeue, + pj_timer_entry *entry); + +/** + * Poll for events. + */ +PJ_DECL(pj_status_t) pj_equeue_poll( pj_equeue_t *equeue, + const pj_time_val *timeout ); + +/** + * Run. + */ +PJ_DECL(pj_status_t) pj_equeue_run( pj_equeue_t *equeue ); + +/** + * Stop all running threads. + */ +PJ_DECL(pj_status_t) pj_equeue_stop( pj_equeue_t *equeue ); + + +/** @} */ + +PJ_END_DECL + +#endif /* __PJ_EQUEUE_H__ */ diff --git a/pjlib/include/pj/errno.h b/pjlib/include/pj/errno.h index 9cc9328d..fee645f6 100644 --- a/pjlib/include/pj/errno.h +++ b/pjlib/include/pj/errno.h @@ -1,249 +1,249 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/errno.h 2 10/14/05 12:26a Bennylp $ */ -#ifndef __PJ_ERRNO_H__ -#define __PJ_ERRNO_H__ - -/** - * @file errno.h - * @brief PJLIB Error Codes - */ -#include -#include - -PJ_BEGIN_DECL - -/** - * @defgroup pj_errno Error Codes - * @ingroup PJ - * @{ - * - * In PJLIB, error/status codes from operating system are translated - * into PJLIB error namespace, and stored in @a pj_status_t. All functions - * that work with @a pj_status_t expect to get PJLIB error code instead - * of native codes. - * - * @section pj_errno_retval Return Values - * - * All functions that returns @a pj_status_t returns @a PJ_SUCCESS if the - * operation was completed successfully, or non-zero value to indicate - * error. If the error came from operating system, then the native error - * code is translated/folded into PJLIB's error namespace by using - * #PJ_STATUS_FROM_OS() macro. The function will do this automatically - * before returning the error to caller. - * - * @section pj_errno_errmsg Error Message - * - * To get the error message corresponding to a particular code, use function - * #pj_strerror(). This function expects error code in PJLIB error namespace, - * not the native error code. Application can pass the value from the - * following sources to this function: - * - #pj_get_os_error() - * - #pj_get_netos_error() - * - any return value from function returning @a pj_status_t. - * - * Application MUST NOT pass native error code (such as error code from - * functions like GetLastError() or errno) to PJLIB functions expecting - * @a pj_status_t. - * - */ - -/** - * Get the last platform error/status, folded into pj_status_t. - * @return OS dependent error code, folded into pj_status_t. - * @remark This function gets errno, or calls GetLastError() function and - * convert the code into pj_status_t with PJ_STATUS_FROM_OS. Do - * not call this for socket functions! - * @see pj_get_netos_error() - */ -PJ_DECL(pj_status_t) pj_get_os_error(void); - -/** - * Set last error. - * @param code pj_status_t - */ -PJ_DECL(void) pj_set_os_error(pj_status_t code); - -/** - * Get the last error from socket operations. - * @return Last socket error, folded into pj_status_t. - */ -PJ_DECL(pj_status_t) pj_get_netos_error(void); - -/** - * Set error code. - * @param code pj_status_t. - */ -PJ_DECL(void) pj_set_netos_error(pj_status_t code); - - -/** - * Get the error message for the specified error code. The message - * string will be NULL terminated. - * - * @param statcode The error code. - * @param buf Buffer to hold the error message string. - * @param bufsize Size of the buffer. - * - * @return The error message as NULL terminated string, - * wrapped with pj_str_t. - */ -PJ_DECL(pj_str_t) pj_strerror( pj_status_t statcode, - char *buf, pj_size_t bufsize); - - -/** - * @hideinitializer - * Return platform os error code folded into pj_status_t code. This is - * the macro that is used throughout the library for all PJLIB's functions - * that returns error from operating system. Application may override - * this macro to reduce size (e.g. by defining it to always return - * #PJ_EUNKNOWN). - * - * Note: - * This macro MUST return non-zero value regardless whether zero is - * passed as the argument. The reason is to protect logic error when - * the operating system doesn't report error codes properly. - * - * @param os_code Platform OS error code. This value may be evaluated - * more than once. - * @return The platform os error code folded into pj_status_t. - */ -#ifndef PJ_RETURN_OS_ERROR -# define PJ_RETURN_OS_ERROR(os_code) (os_code ? \ - PJ_STATUS_FROM_OS(os_code) : -1) -#endif - - -/** - * @hideinitializer - * Fold a platform specific error into an pj_status_t code. - * - * @param e The platform os error code. - * @return pj_status_t - * @warning Macro implementation; the syserr argument may be evaluated - * multiple times. - */ -#define PJ_STATUS_FROM_OS(e) (e == 0 ? PJ_SUCCESS : e + PJ_ERRNO_START_SYS) - -/** - * @hideinitializer - * Fold an pj_status_t code back to the native platform defined error. - * - * @param e The pj_status_t folded platform os error code. - * @return pj_os_err_type - * @warning macro implementation; the statcode argument may be evaluated - * multiple times. If the statcode was not created by - * pj_get_os_error or PJ_STATUS_FROM_OS, the results are undefined. - */ -#define PJ_STATUS_TO_OS(e) (e == 0 ? PJ_SUCCESS : e - PJ_ERRNO_START_SYS) - - -/** - * @defgroup pj_errnum PJLIB's Own Error Codes - * @ingroup pj_errno - * @{ - */ - -/** - * @hideinitializer - * Unknown error has been reported. - */ -#define PJ_EUNKNOWN (PJ_ERRNO_START_STATUS + 1) -/** - * @hideinitializer - * The operation is pending and will be completed later. - */ -#define PJ_EPENDING (PJ_ERRNO_START_STATUS + 2) -/** - * @hideinitializer - * Too many connecting sockets. - */ -#define PJ_ETOOMANYCONN (PJ_ERRNO_START_STATUS + 3) -/** - * @hideinitializer - * Invalid argument. - */ -#define PJ_EINVAL (PJ_ERRNO_START_STATUS + 4) -/** - * @hideinitializer - * Name too long (eg. hostname too long). - */ -#define PJ_ENAMETOOLONG (PJ_ERRNO_START_STATUS + 5) -/** - * @hideinitializer - * Not found. - */ -#define PJ_ENOTFOUND (PJ_ERRNO_START_STATUS + 6) -/** - * @hideinitializer - * Not enough memory. - */ -#define PJ_ENOMEM (PJ_ERRNO_START_STATUS + 7) -/** - * @hideinitializer - * Bug detected! - */ -#define PJ_EBUG (PJ_ERRNO_START_STATUS + 8) -/** - * @hideinitializer - * Operation timed out. - */ -#define PJ_ETIMEDOUT (PJ_ERRNO_START_STATUS + 9) -/** - * @hideinitializer - * Too many objects. - */ -#define PJ_ETOOMANY (PJ_ERRNO_START_STATUS + 10) -/** - * @hideinitializer - * Object is busy. - */ -#define PJ_EBUSY (PJ_ERRNO_START_STATUS + 11) -/** - * @hideinitializer - * The specified option is not supported. - */ -#define PJ_ENOTSUP (PJ_ERRNO_START_STATUS + 12) -/** - * @hideinitializer - * Invalid operation. - */ -#define PJ_EINVALIDOP (PJ_ERRNO_START_STATUS + 13) - -/** @} */ /* pj_errnum */ - -/** @} */ /* pj_errno */ - - -/** - * PJ_ERRNO_START is where PJLIB specific error values start. - */ -#define PJ_ERRNO_START 20000 - -/** - * PJ_ERRNO_SPACE_SIZE is the maximum number of errors in one of - * the error/status range below. - */ -#define PJ_ERRNO_SPACE_SIZE 50000 - -/** - * PJ_ERRNO_START_STATUS is where PJLIB specific status codes start. - */ -#define PJ_ERRNO_START_STATUS (PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) - -/** - * PJ_ERRNO_START_SYS converts platform specific error codes into - * pj_status_t values. - */ -#define PJ_ERRNO_START_SYS (PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE) - -/** - * PJ_ERRNO_START_USER are reserved for applications that use error - * codes along with PJLIB codes. - */ -#define PJ_ERRNO_START_USER (PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE) - - -PJ_END_DECL - -#endif /* __PJ_ERRNO_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/errno.h 2 10/14/05 12:26a Bennylp $ */ +#ifndef __PJ_ERRNO_H__ +#define __PJ_ERRNO_H__ + +/** + * @file errno.h + * @brief PJLIB Error Codes + */ +#include +#include + +PJ_BEGIN_DECL + +/** + * @defgroup pj_errno Error Codes + * @ingroup PJ + * @{ + * + * In PJLIB, error/status codes from operating system are translated + * into PJLIB error namespace, and stored in @a pj_status_t. All functions + * that work with @a pj_status_t expect to get PJLIB error code instead + * of native codes. + * + * @section pj_errno_retval Return Values + * + * All functions that returns @a pj_status_t returns @a PJ_SUCCESS if the + * operation was completed successfully, or non-zero value to indicate + * error. If the error came from operating system, then the native error + * code is translated/folded into PJLIB's error namespace by using + * #PJ_STATUS_FROM_OS() macro. The function will do this automatically + * before returning the error to caller. + * + * @section pj_errno_errmsg Error Message + * + * To get the error message corresponding to a particular code, use function + * #pj_strerror(). This function expects error code in PJLIB error namespace, + * not the native error code. Application can pass the value from the + * following sources to this function: + * - #pj_get_os_error() + * - #pj_get_netos_error() + * - any return value from function returning @a pj_status_t. + * + * Application MUST NOT pass native error code (such as error code from + * functions like GetLastError() or errno) to PJLIB functions expecting + * @a pj_status_t. + * + */ + +/** + * Get the last platform error/status, folded into pj_status_t. + * @return OS dependent error code, folded into pj_status_t. + * @remark This function gets errno, or calls GetLastError() function and + * convert the code into pj_status_t with PJ_STATUS_FROM_OS. Do + * not call this for socket functions! + * @see pj_get_netos_error() + */ +PJ_DECL(pj_status_t) pj_get_os_error(void); + +/** + * Set last error. + * @param code pj_status_t + */ +PJ_DECL(void) pj_set_os_error(pj_status_t code); + +/** + * Get the last error from socket operations. + * @return Last socket error, folded into pj_status_t. + */ +PJ_DECL(pj_status_t) pj_get_netos_error(void); + +/** + * Set error code. + * @param code pj_status_t. + */ +PJ_DECL(void) pj_set_netos_error(pj_status_t code); + + +/** + * Get the error message for the specified error code. The message + * string will be NULL terminated. + * + * @param statcode The error code. + * @param buf Buffer to hold the error message string. + * @param bufsize Size of the buffer. + * + * @return The error message as NULL terminated string, + * wrapped with pj_str_t. + */ +PJ_DECL(pj_str_t) pj_strerror( pj_status_t statcode, + char *buf, pj_size_t bufsize); + + +/** + * @hideinitializer + * Return platform os error code folded into pj_status_t code. This is + * the macro that is used throughout the library for all PJLIB's functions + * that returns error from operating system. Application may override + * this macro to reduce size (e.g. by defining it to always return + * #PJ_EUNKNOWN). + * + * Note: + * This macro MUST return non-zero value regardless whether zero is + * passed as the argument. The reason is to protect logic error when + * the operating system doesn't report error codes properly. + * + * @param os_code Platform OS error code. This value may be evaluated + * more than once. + * @return The platform os error code folded into pj_status_t. + */ +#ifndef PJ_RETURN_OS_ERROR +# define PJ_RETURN_OS_ERROR(os_code) (os_code ? \ + PJ_STATUS_FROM_OS(os_code) : -1) +#endif + + +/** + * @hideinitializer + * Fold a platform specific error into an pj_status_t code. + * + * @param e The platform os error code. + * @return pj_status_t + * @warning Macro implementation; the syserr argument may be evaluated + * multiple times. + */ +#define PJ_STATUS_FROM_OS(e) (e == 0 ? PJ_SUCCESS : e + PJ_ERRNO_START_SYS) + +/** + * @hideinitializer + * Fold an pj_status_t code back to the native platform defined error. + * + * @param e The pj_status_t folded platform os error code. + * @return pj_os_err_type + * @warning macro implementation; the statcode argument may be evaluated + * multiple times. If the statcode was not created by + * pj_get_os_error or PJ_STATUS_FROM_OS, the results are undefined. + */ +#define PJ_STATUS_TO_OS(e) (e == 0 ? PJ_SUCCESS : e - PJ_ERRNO_START_SYS) + + +/** + * @defgroup pj_errnum PJLIB's Own Error Codes + * @ingroup pj_errno + * @{ + */ + +/** + * @hideinitializer + * Unknown error has been reported. + */ +#define PJ_EUNKNOWN (PJ_ERRNO_START_STATUS + 1) +/** + * @hideinitializer + * The operation is pending and will be completed later. + */ +#define PJ_EPENDING (PJ_ERRNO_START_STATUS + 2) +/** + * @hideinitializer + * Too many connecting sockets. + */ +#define PJ_ETOOMANYCONN (PJ_ERRNO_START_STATUS + 3) +/** + * @hideinitializer + * Invalid argument. + */ +#define PJ_EINVAL (PJ_ERRNO_START_STATUS + 4) +/** + * @hideinitializer + * Name too long (eg. hostname too long). + */ +#define PJ_ENAMETOOLONG (PJ_ERRNO_START_STATUS + 5) +/** + * @hideinitializer + * Not found. + */ +#define PJ_ENOTFOUND (PJ_ERRNO_START_STATUS + 6) +/** + * @hideinitializer + * Not enough memory. + */ +#define PJ_ENOMEM (PJ_ERRNO_START_STATUS + 7) +/** + * @hideinitializer + * Bug detected! + */ +#define PJ_EBUG (PJ_ERRNO_START_STATUS + 8) +/** + * @hideinitializer + * Operation timed out. + */ +#define PJ_ETIMEDOUT (PJ_ERRNO_START_STATUS + 9) +/** + * @hideinitializer + * Too many objects. + */ +#define PJ_ETOOMANY (PJ_ERRNO_START_STATUS + 10) +/** + * @hideinitializer + * Object is busy. + */ +#define PJ_EBUSY (PJ_ERRNO_START_STATUS + 11) +/** + * @hideinitializer + * The specified option is not supported. + */ +#define PJ_ENOTSUP (PJ_ERRNO_START_STATUS + 12) +/** + * @hideinitializer + * Invalid operation. + */ +#define PJ_EINVALIDOP (PJ_ERRNO_START_STATUS + 13) + +/** @} */ /* pj_errnum */ + +/** @} */ /* pj_errno */ + + +/** + * PJ_ERRNO_START is where PJLIB specific error values start. + */ +#define PJ_ERRNO_START 20000 + +/** + * PJ_ERRNO_SPACE_SIZE is the maximum number of errors in one of + * the error/status range below. + */ +#define PJ_ERRNO_SPACE_SIZE 50000 + +/** + * PJ_ERRNO_START_STATUS is where PJLIB specific status codes start. + */ +#define PJ_ERRNO_START_STATUS (PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) + +/** + * PJ_ERRNO_START_SYS converts platform specific error codes into + * pj_status_t values. + */ +#define PJ_ERRNO_START_SYS (PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE) + +/** + * PJ_ERRNO_START_USER are reserved for applications that use error + * codes along with PJLIB codes. + */ +#define PJ_ERRNO_START_USER (PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE) + + +PJ_END_DECL + +#endif /* __PJ_ERRNO_H__ */ + diff --git a/pjlib/include/pj/except.h b/pjlib/include/pj/except.h index b325b47c..4a2505bb 100644 --- a/pjlib/include/pj/except.h +++ b/pjlib/include/pj/except.h @@ -1,267 +1,267 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/except.h 9 10/14/05 12:26a Bennylp $ */ - -#ifndef __PJ_EXCEPTION_H__ -#define __PJ_EXCEPTION_H__ - -/** - * @file except.h - * @brief Exception Handling in C. - */ - -#include -#include - - -PJ_BEGIN_DECL - - -/** - * @defgroup PJ_EXCEPT Exception Handling - * @ingroup PJ_MISC - * @{ - * - * \section pj_except_sample_sec Quick Example - * - * For the impatient, take a look at some examples: - * - @ref page_pjlib_samples_except_c - * - @ref page_pjlib_exception_test - * - * \section pj_except_except Exception Handling - * - * This module provides exception handling syntactically similar to C++ in - * C language. The underlying mechanism use setjmp() and longjmp(), and since - * these constructs are ANSI standard, the mechanism here should be available - * on most platforms/compilers which are ANSI compliant. - * - * If ANSI libc is not available, then setjmp()/longjmp() implementation will - * be provided. See for compatibility. - * - * The exception handling mechanism is completely thread safe, so the exception - * thrown by one thread will not interfere with other thread. - * - * CAVEATS: - * - unlike C++ exception, the scheme here won't call destructors of local - * objects if exception is thrown. Care must be taken when a function - * hold some resorce such as pool or mutex etc. - * - You CAN NOT make nested exception in one single function without using - * a nested PJ_USE_EXCEPTION. - * - Exceptions will always be caught by the first handle (unlike C++ where - * exception is only caught if the type matches. - * - * The exception handling constructs are similar to C++. The blocks will be - * constructed similar to the following sample: - * - * \verbatim - #define NO_MEMORY 1 - #define SYNTAX_ERROR 2 - - int main() - { - PJ_USE_EXCEPTION; // declare local exception stack. - - PJ_TRY { - ...// do something.. - } - PJ_CATCH(NO_MEMORY) { - ... // handle exception 1 - } - PJ_CATCH(SYNTAX_ERROR) { - ... // handle exception 2 - } - PJ_DEFAULT { - ... // handle other exceptions. - } - PJ_END; - } - \endverbatim - * - * The above sample uses hard coded exception ID. It is @b strongly - * recommended that applications request a unique exception ID instead - * of hard coded value like above. - * - * \section pj_except_reg Exception ID Allocation - * - * To ensure that exception ID (number) are used consistently and to - * prevent ID collisions in an application, it is strongly suggested that - * applications allocate an exception ID for each possible exception - * type. As a bonus of this process, the application can identify - * the name of the exception when the particular exception is thrown. - * - * Exception ID management are performed with the following APIs: - * - #pj_exception_id_alloc(). - * - #pj_exception_id_free(). - * - #pj_exception_id_name(). - * - * - * PJLIB itself automatically allocates one exception id, i.e. - * #PJ_NO_MEMORY_EXCEPTION which is declared in . This exception - * ID is raised by default pool policy when it fails to allocate memory. - * - * \section PJ_EX_KEYWORDS Keywords - * - * \subsection PJ_THROW PJ_THROW(expression) - * Throw an exception. The expression thrown is an integer as the result of - * the \a expression. This keyword can be specified anywhere within the - * program. - * - * \subsection PJ_USE_EXCEPTION PJ_USE_EXCEPTION - * Specify this in the variable definition section of the function block - * (or any blocks) to specify that the block has \a PJ_TRY/PJ_CATCH exception - * block. - * Actually, this is just a macro to declare local variable which is used to - * push the exception state to the exception stack. - * - * \subsection PJ_TRY PJ_TRY - * The \a PJ_TRY keyword is typically followed by a block. If an exception is - * thrown in this block, then the execution will resume to the \a PJ_CATCH - * handler. - * - * \subsection PJ_CATCH PJ_CATCH(expression) - * The \a PJ_CATCH is normally followed by a block. This block will be executed - * if the exception being thrown is equal to the expression specified in the - * \a PJ_CATCH. - * - * \subsection PJ_DEFAULT PJ_DEFAULT - * The \a PJ_DEFAULT keyword is normally followed by a block. This block will - * be executed if the exception being thrown doesn't match any of the \a - * PJ_CATCH specification. The \a PJ_DEFAULT block \b MUST be placed as the - * last block of the handlers. - * - * \subsection PJ_END PJ_END - * Specify this keyword to mark the end of \a PJ_TRY / \a PJ_CATCH blocks. - * - * \subsection PJ_GET_EXCEPTION PJ_GET_EXCEPTION(void) - * Get the last exception thrown. This macro is normally called inside the - * \a PJ_CATCH or \a PJ_DEFAULT block, altough it can be used anywhere where - * the \a PJ_USE_EXCEPTION definition is in scope. - * - * - * \section pj_except_examples_sec Examples - * - * For some examples on how to use the exception construct, please see: - * - @ref page_pjlib_samples_except_c - * - @ref page_pjlib_exception_test - */ - -/** - * Allocate a unique exception id. - * Applications don't have to allocate a unique exception ID before using - * the exception construct. However, by doing so it ensures that there is - * no collisions of exception ID. - * - * As a bonus, when exception number is acquired through this function, - * the library can assign name to the exception (only if - * PJ_HAS_EXCEPTION_NAMES is enabled (default is yes)) and find out the - * exception name when it catches an exception. - * - * @param name Name to be associated with the exception ID. - * @param id Pointer to receive the ID. - * - * @return PJ_SUCCESS on success or PJ_ETOOMANY if the library - * is running out out ids. - */ -PJ_DECL(pj_status_t) pj_exception_id_alloc(const char *name, - pj_exception_id_t *id); - -/** - * Free an exception id. - * - * @param id The exception ID. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_exception_id_free(pj_exception_id_t id); - -/** - * Retrieve name associated with the exception id. - * - * @param id The exception ID. - * - * @return The name associated with the specified ID. - */ -PJ_DECL(const char*) pj_exception_id_name(pj_exception_id_t id); - -/** @} */ - -/** - * This structure (which should be invisible to user) manages the TRY handler - * stack. - */ -struct pj_exception_state_t -{ - struct pj_exception_state_t *prev; /**< Previous state in the list. */ - pj_jmp_buf state; /**< jmp_buf. */ -}; - -/** - * Throw exception. - * @param id Exception Id. - */ -PJ_DECL_NO_RETURN(void) -pj_throw_exception_(pj_exception_id_t id) PJ_ATTR_NORETURN; - -/** - * Push exception handler. - */ -PJ_DECL(void) pj_push_exception_handler_(struct pj_exception_state_t *rec); - -/** - * Pop exception handler. - */ -PJ_DECL(void) pj_pop_exception_handler_(void); - -/** - * Declare that the function will use exception. - * @hideinitializer - */ -#define PJ_USE_EXCEPTION struct pj_exception_state_t pj_x_except__; int pj_x_code__ - -/** - * Start exception specification block. - * @hideinitializer - */ -#define PJ_TRY if (1) { \ - pj_push_exception_handler_(&pj_x_except__); \ - pj_x_code__ = pj_setjmp(pj_x_except__.state); \ - if (pj_x_code__ == 0) -/** - * Catch the specified exception Id. - * @param id The exception number to catch. - * @hideinitializer - */ -#define PJ_CATCH(id) else if (pj_x_code__ == (id)) - -/** - * Catch any exception number. - * @hideinitializer - */ -#define PJ_DEFAULT else - -/** - * End of exception specification block. - * @hideinitializer - */ -#define PJ_END pj_pop_exception_handler_(); \ - } else {} - -/** - * Throw exception. - * @param exception_id The exception number. - * @hideinitializer - */ -#define PJ_THROW(exception_id) pj_throw_exception_(exception_id) - -/** - * Get current exception. - * @return Current exception code. - * @hideinitializer - */ -#define PJ_GET_EXCEPTION() (pj_x_code__) - -PJ_END_DECL - - - -#endif /* __PJ_EXCEPTION_H__ */ - - +/* $Header: /pjproject-0.3/pjlib/include/pj/except.h 9 10/14/05 12:26a Bennylp $ */ + +#ifndef __PJ_EXCEPTION_H__ +#define __PJ_EXCEPTION_H__ + +/** + * @file except.h + * @brief Exception Handling in C. + */ + +#include +#include + + +PJ_BEGIN_DECL + + +/** + * @defgroup PJ_EXCEPT Exception Handling + * @ingroup PJ_MISC + * @{ + * + * \section pj_except_sample_sec Quick Example + * + * For the impatient, take a look at some examples: + * - @ref page_pjlib_samples_except_c + * - @ref page_pjlib_exception_test + * + * \section pj_except_except Exception Handling + * + * This module provides exception handling syntactically similar to C++ in + * C language. The underlying mechanism use setjmp() and longjmp(), and since + * these constructs are ANSI standard, the mechanism here should be available + * on most platforms/compilers which are ANSI compliant. + * + * If ANSI libc is not available, then setjmp()/longjmp() implementation will + * be provided. See for compatibility. + * + * The exception handling mechanism is completely thread safe, so the exception + * thrown by one thread will not interfere with other thread. + * + * CAVEATS: + * - unlike C++ exception, the scheme here won't call destructors of local + * objects if exception is thrown. Care must be taken when a function + * hold some resorce such as pool or mutex etc. + * - You CAN NOT make nested exception in one single function without using + * a nested PJ_USE_EXCEPTION. + * - Exceptions will always be caught by the first handle (unlike C++ where + * exception is only caught if the type matches. + * + * The exception handling constructs are similar to C++. The blocks will be + * constructed similar to the following sample: + * + * \verbatim + #define NO_MEMORY 1 + #define SYNTAX_ERROR 2 + + int main() + { + PJ_USE_EXCEPTION; // declare local exception stack. + + PJ_TRY { + ...// do something.. + } + PJ_CATCH(NO_MEMORY) { + ... // handle exception 1 + } + PJ_CATCH(SYNTAX_ERROR) { + ... // handle exception 2 + } + PJ_DEFAULT { + ... // handle other exceptions. + } + PJ_END; + } + \endverbatim + * + * The above sample uses hard coded exception ID. It is @b strongly + * recommended that applications request a unique exception ID instead + * of hard coded value like above. + * + * \section pj_except_reg Exception ID Allocation + * + * To ensure that exception ID (number) are used consistently and to + * prevent ID collisions in an application, it is strongly suggested that + * applications allocate an exception ID for each possible exception + * type. As a bonus of this process, the application can identify + * the name of the exception when the particular exception is thrown. + * + * Exception ID management are performed with the following APIs: + * - #pj_exception_id_alloc(). + * - #pj_exception_id_free(). + * - #pj_exception_id_name(). + * + * + * PJLIB itself automatically allocates one exception id, i.e. + * #PJ_NO_MEMORY_EXCEPTION which is declared in . This exception + * ID is raised by default pool policy when it fails to allocate memory. + * + * \section PJ_EX_KEYWORDS Keywords + * + * \subsection PJ_THROW PJ_THROW(expression) + * Throw an exception. The expression thrown is an integer as the result of + * the \a expression. This keyword can be specified anywhere within the + * program. + * + * \subsection PJ_USE_EXCEPTION PJ_USE_EXCEPTION + * Specify this in the variable definition section of the function block + * (or any blocks) to specify that the block has \a PJ_TRY/PJ_CATCH exception + * block. + * Actually, this is just a macro to declare local variable which is used to + * push the exception state to the exception stack. + * + * \subsection PJ_TRY PJ_TRY + * The \a PJ_TRY keyword is typically followed by a block. If an exception is + * thrown in this block, then the execution will resume to the \a PJ_CATCH + * handler. + * + * \subsection PJ_CATCH PJ_CATCH(expression) + * The \a PJ_CATCH is normally followed by a block. This block will be executed + * if the exception being thrown is equal to the expression specified in the + * \a PJ_CATCH. + * + * \subsection PJ_DEFAULT PJ_DEFAULT + * The \a PJ_DEFAULT keyword is normally followed by a block. This block will + * be executed if the exception being thrown doesn't match any of the \a + * PJ_CATCH specification. The \a PJ_DEFAULT block \b MUST be placed as the + * last block of the handlers. + * + * \subsection PJ_END PJ_END + * Specify this keyword to mark the end of \a PJ_TRY / \a PJ_CATCH blocks. + * + * \subsection PJ_GET_EXCEPTION PJ_GET_EXCEPTION(void) + * Get the last exception thrown. This macro is normally called inside the + * \a PJ_CATCH or \a PJ_DEFAULT block, altough it can be used anywhere where + * the \a PJ_USE_EXCEPTION definition is in scope. + * + * + * \section pj_except_examples_sec Examples + * + * For some examples on how to use the exception construct, please see: + * - @ref page_pjlib_samples_except_c + * - @ref page_pjlib_exception_test + */ + +/** + * Allocate a unique exception id. + * Applications don't have to allocate a unique exception ID before using + * the exception construct. However, by doing so it ensures that there is + * no collisions of exception ID. + * + * As a bonus, when exception number is acquired through this function, + * the library can assign name to the exception (only if + * PJ_HAS_EXCEPTION_NAMES is enabled (default is yes)) and find out the + * exception name when it catches an exception. + * + * @param name Name to be associated with the exception ID. + * @param id Pointer to receive the ID. + * + * @return PJ_SUCCESS on success or PJ_ETOOMANY if the library + * is running out out ids. + */ +PJ_DECL(pj_status_t) pj_exception_id_alloc(const char *name, + pj_exception_id_t *id); + +/** + * Free an exception id. + * + * @param id The exception ID. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_exception_id_free(pj_exception_id_t id); + +/** + * Retrieve name associated with the exception id. + * + * @param id The exception ID. + * + * @return The name associated with the specified ID. + */ +PJ_DECL(const char*) pj_exception_id_name(pj_exception_id_t id); + +/** @} */ + +/** + * This structure (which should be invisible to user) manages the TRY handler + * stack. + */ +struct pj_exception_state_t +{ + struct pj_exception_state_t *prev; /**< Previous state in the list. */ + pj_jmp_buf state; /**< jmp_buf. */ +}; + +/** + * Throw exception. + * @param id Exception Id. + */ +PJ_DECL_NO_RETURN(void) +pj_throw_exception_(pj_exception_id_t id) PJ_ATTR_NORETURN; + +/** + * Push exception handler. + */ +PJ_DECL(void) pj_push_exception_handler_(struct pj_exception_state_t *rec); + +/** + * Pop exception handler. + */ +PJ_DECL(void) pj_pop_exception_handler_(void); + +/** + * Declare that the function will use exception. + * @hideinitializer + */ +#define PJ_USE_EXCEPTION struct pj_exception_state_t pj_x_except__; int pj_x_code__ + +/** + * Start exception specification block. + * @hideinitializer + */ +#define PJ_TRY if (1) { \ + pj_push_exception_handler_(&pj_x_except__); \ + pj_x_code__ = pj_setjmp(pj_x_except__.state); \ + if (pj_x_code__ == 0) +/** + * Catch the specified exception Id. + * @param id The exception number to catch. + * @hideinitializer + */ +#define PJ_CATCH(id) else if (pj_x_code__ == (id)) + +/** + * Catch any exception number. + * @hideinitializer + */ +#define PJ_DEFAULT else + +/** + * End of exception specification block. + * @hideinitializer + */ +#define PJ_END pj_pop_exception_handler_(); \ + } else {} + +/** + * Throw exception. + * @param exception_id The exception number. + * @hideinitializer + */ +#define PJ_THROW(exception_id) pj_throw_exception_(exception_id) + +/** + * Get current exception. + * @return Current exception code. + * @hideinitializer + */ +#define PJ_GET_EXCEPTION() (pj_x_code__) + +PJ_END_DECL + + + +#endif /* __PJ_EXCEPTION_H__ */ + + diff --git a/pjlib/include/pj/fifobuf.h b/pjlib/include/pj/fifobuf.h index 45f91b17..5c4c78d7 100644 --- a/pjlib/include/pj/fifobuf.h +++ b/pjlib/include/pj/fifobuf.h @@ -1,27 +1,27 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/fifobuf.h 4 10/14/05 12:26a Bennylp $ */ - -#ifndef __PJ_FIFOBUF_H__ -#define __PJ_FIFOBUF_H__ - -#include - -PJ_BEGIN_DECL - -typedef struct pj_fifobuf_t pj_fifobuf_t; -struct pj_fifobuf_t -{ - char *first, *last; - char *ubegin, *uend; - int full; -}; - -PJ_DECL(void) pj_fifobuf_init (pj_fifobuf_t *fb, void *buffer, unsigned size); -PJ_DECL(unsigned) pj_fifobuf_max_size (pj_fifobuf_t *fb); -PJ_DECL(void*) pj_fifobuf_alloc (pj_fifobuf_t *fb, unsigned size); -PJ_DECL(pj_status_t) pj_fifobuf_unalloc (pj_fifobuf_t *fb, void *buf); -PJ_DECL(pj_status_t) pj_fifobuf_free (pj_fifobuf_t *fb, void *buf); - -PJ_END_DECL - -#endif /* __PJ_FIFOBUF_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/fifobuf.h 4 10/14/05 12:26a Bennylp $ */ + +#ifndef __PJ_FIFOBUF_H__ +#define __PJ_FIFOBUF_H__ + +#include + +PJ_BEGIN_DECL + +typedef struct pj_fifobuf_t pj_fifobuf_t; +struct pj_fifobuf_t +{ + char *first, *last; + char *ubegin, *uend; + int full; +}; + +PJ_DECL(void) pj_fifobuf_init (pj_fifobuf_t *fb, void *buffer, unsigned size); +PJ_DECL(unsigned) pj_fifobuf_max_size (pj_fifobuf_t *fb); +PJ_DECL(void*) pj_fifobuf_alloc (pj_fifobuf_t *fb, unsigned size); +PJ_DECL(pj_status_t) pj_fifobuf_unalloc (pj_fifobuf_t *fb, void *buf); +PJ_DECL(pj_status_t) pj_fifobuf_free (pj_fifobuf_t *fb, void *buf); + +PJ_END_DECL + +#endif /* __PJ_FIFOBUF_H__ */ + diff --git a/pjlib/include/pj/guid.h b/pjlib/include/pj/guid.h index 7dccf7fb..652b5474 100644 --- a/pjlib/include/pj/guid.h +++ b/pjlib/include/pj/guid.h @@ -1,75 +1,75 @@ -/* $header: $ */ - -#ifndef __PJ_GUID_H__ -#define __PJ_GUID_H__ - - -/** - * @file guid.h - * @brief GUID Globally Unique Identifier. - */ -#include - - -PJ_BEGIN_DECL - - -/** - * @defgroup PJ_DS Data Structure. - * @ingroup PJ - */ -/** - * @defgroup PJ_GUID Globally Unique Identifier - * @ingroup PJ_DS - * @{ - * - * This module provides API to create string that is globally unique. - * If application doesn't require that strong requirement, it can just - * use #pj_create_random_string() instead. - */ - - -/** - * PJ_GUID_STRING_LENGTH specifies length of GUID string. The value is - * dependent on the algorithm used internally to generate the GUID string. - * If real GUID generator is used, then the length will be 128bit or - * 32 bytes. If shadow GUID generator is used, then the length - * will be 20 bytes. Application should not assume which algorithm will - * be used by GUID generator. - */ -extern const unsigned PJ_GUID_STRING_LENGTH; - -/** - * PJ_GUID_MAX_LENGTH specifies the maximum length of GUID string, - * regardless of which algorithm to use. - */ -#define PJ_GUID_MAX_LENGTH 32 - -/** - * Create a globally unique string, which length is PJ_GUID_STRING_LENGTH - * characters. Caller is responsible for preallocating the storage used - * in the string. - * - * @param str The string to store the result. - * - * @return The string. - */ -PJ_DECL(pj_str_t*) pj_generate_unique_string(pj_str_t *str); - -/** - * Generate a unique string. - * - * @param pool Pool to allocate memory from. - * @param str The string. - */ -PJ_DECL(void) pj_create_unique_string(pj_pool_t *pool, pj_str_t *str); - - -/** - * @} - */ - -PJ_END_DECL - -#endif/* __PJ_GUID_H__ */ - +/* $header: $ */ + +#ifndef __PJ_GUID_H__ +#define __PJ_GUID_H__ + + +/** + * @file guid.h + * @brief GUID Globally Unique Identifier. + */ +#include + + +PJ_BEGIN_DECL + + +/** + * @defgroup PJ_DS Data Structure. + * @ingroup PJ + */ +/** + * @defgroup PJ_GUID Globally Unique Identifier + * @ingroup PJ_DS + * @{ + * + * This module provides API to create string that is globally unique. + * If application doesn't require that strong requirement, it can just + * use #pj_create_random_string() instead. + */ + + +/** + * PJ_GUID_STRING_LENGTH specifies length of GUID string. The value is + * dependent on the algorithm used internally to generate the GUID string. + * If real GUID generator is used, then the length will be 128bit or + * 32 bytes. If shadow GUID generator is used, then the length + * will be 20 bytes. Application should not assume which algorithm will + * be used by GUID generator. + */ +extern const unsigned PJ_GUID_STRING_LENGTH; + +/** + * PJ_GUID_MAX_LENGTH specifies the maximum length of GUID string, + * regardless of which algorithm to use. + */ +#define PJ_GUID_MAX_LENGTH 32 + +/** + * Create a globally unique string, which length is PJ_GUID_STRING_LENGTH + * characters. Caller is responsible for preallocating the storage used + * in the string. + * + * @param str The string to store the result. + * + * @return The string. + */ +PJ_DECL(pj_str_t*) pj_generate_unique_string(pj_str_t *str); + +/** + * Generate a unique string. + * + * @param pool Pool to allocate memory from. + * @param str The string. + */ +PJ_DECL(void) pj_create_unique_string(pj_pool_t *pool, pj_str_t *str); + + +/** + * @} + */ + +PJ_END_DECL + +#endif/* __PJ_GUID_H__ */ + diff --git a/pjlib/include/pj/hash.h b/pjlib/include/pj/hash.h index f475dcc0..e0555c37 100644 --- a/pjlib/include/pj/hash.h +++ b/pjlib/include/pj/hash.h @@ -1,140 +1,140 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/hash.h 6 10/14/05 12:26a Bennylp $ */ - -#ifndef __PJ_HASH_H__ -#define __PJ_HASH_H__ - -/** - * @file hash.h - * @brief Hash Table. - */ - -#include - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_HASH Hash Table - * @ingroup PJ_DS - * @{ - * A hash table is a dictionary in which keys are mapped to array positions by - * hash functions. Having the keys of more than one item map to the same - * position is called a collision. In this library, we will chain the nodes - * that have the same key in a list. - */ - -/** - * If this constant is used as keylen, then the key is interpreted as - * NULL terminated string. - */ -#define PJ_HASH_KEY_STRING ((unsigned)-1) - -/** - * This is the function that is used by the hash table to calculate hash value - * of the specified key. - * - * @param hval the initial hash value, or zero. - * @param key the key to calculate. - * @param keylen the length of the key, or PJ_HASH_KEY_STRING to treat - * the key as null terminated string. - * - * @return the hash value. - */ -PJ_DECL(pj_uint32_t) pj_hash_calc(pj_uint32_t hval, - const void *key, unsigned keylen); - - -/** - * Create a hash table with the specified 'bucket' size. - * - * @param pool the pool from which the hash table will be allocated from. - * @param size the bucket size, which will be round-up to the nearest 2^n+1 - * - * @return the hash table. - */ -PJ_DECL(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size); - - -/** - * Get the value associated with the specified key. - * - * @param ht the hash table. - * @param key the key to look for. - * @param keylen the length of the key, or PJ_HASH_KEY_STRING to use the - * string length of the key. - * - * @return the value associated with the key, or NULL if the key is not found. - */ -PJ_DECL(void *) pj_hash_get( pj_hash_table_t *ht, - const void *key, unsigned keylen ); - - -/** - * Associate/disassociate a value with the specified key. - * - * @param pool the pool to allocate the new entry if a new entry has to be - * created. - * @param ht the hash table. - * @param key the key. - * @param keylen the length of the key, or PJ_HASH_KEY_STRING to use the - * string length of the key. - * @param value value to be associated, or NULL to delete the entry with - * the specified key. - */ -PJ_DECL(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht, - const void *key, unsigned keylen, - void *value ); - -/** - * Get the total number of entries in the hash table. - * - * @param ht the hash table. - * - * @return the number of entries in the hash table. - */ -PJ_DECL(unsigned) pj_hash_count( pj_hash_table_t *ht ); - - -/** - * Get the iterator to the first element in the hash table. - * - * @param ht the hash table. - * @param it the iterator for iterating hash elements. - * - * @return the iterator to the hash element, or NULL if no element presents. - */ -PJ_DECL(pj_hash_iterator_t*) pj_hash_first( pj_hash_table_t *ht, - pj_hash_iterator_t *it ); - - -/** - * Get the next element from the iterator. - * - * @param ht the hash table. - * @param it the hash iterator. - * - * @return the next iterator, or NULL if there's no more element. - */ -PJ_DECL(pj_hash_iterator_t*) pj_hash_next( pj_hash_table_t *ht, - pj_hash_iterator_t *it ); - -/** - * Get the value associated with a hash iterator. - * - * @param ht the hash table. - * @param it the hash iterator. - * - * @return the value associated with the current element in iterator. - */ -PJ_DECL(void*) pj_hash_this( pj_hash_table_t *ht, - pj_hash_iterator_t *it ); - - -/** - * @} - */ - -PJ_END_DECL - -#endif - - +/* $Header: /pjproject-0.3/pjlib/include/pj/hash.h 6 10/14/05 12:26a Bennylp $ */ + +#ifndef __PJ_HASH_H__ +#define __PJ_HASH_H__ + +/** + * @file hash.h + * @brief Hash Table. + */ + +#include + +PJ_BEGIN_DECL + +/** + * @defgroup PJ_HASH Hash Table + * @ingroup PJ_DS + * @{ + * A hash table is a dictionary in which keys are mapped to array positions by + * hash functions. Having the keys of more than one item map to the same + * position is called a collision. In this library, we will chain the nodes + * that have the same key in a list. + */ + +/** + * If this constant is used as keylen, then the key is interpreted as + * NULL terminated string. + */ +#define PJ_HASH_KEY_STRING ((unsigned)-1) + +/** + * This is the function that is used by the hash table to calculate hash value + * of the specified key. + * + * @param hval the initial hash value, or zero. + * @param key the key to calculate. + * @param keylen the length of the key, or PJ_HASH_KEY_STRING to treat + * the key as null terminated string. + * + * @return the hash value. + */ +PJ_DECL(pj_uint32_t) pj_hash_calc(pj_uint32_t hval, + const void *key, unsigned keylen); + + +/** + * Create a hash table with the specified 'bucket' size. + * + * @param pool the pool from which the hash table will be allocated from. + * @param size the bucket size, which will be round-up to the nearest 2^n+1 + * + * @return the hash table. + */ +PJ_DECL(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size); + + +/** + * Get the value associated with the specified key. + * + * @param ht the hash table. + * @param key the key to look for. + * @param keylen the length of the key, or PJ_HASH_KEY_STRING to use the + * string length of the key. + * + * @return the value associated with the key, or NULL if the key is not found. + */ +PJ_DECL(void *) pj_hash_get( pj_hash_table_t *ht, + const void *key, unsigned keylen ); + + +/** + * Associate/disassociate a value with the specified key. + * + * @param pool the pool to allocate the new entry if a new entry has to be + * created. + * @param ht the hash table. + * @param key the key. + * @param keylen the length of the key, or PJ_HASH_KEY_STRING to use the + * string length of the key. + * @param value value to be associated, or NULL to delete the entry with + * the specified key. + */ +PJ_DECL(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht, + const void *key, unsigned keylen, + void *value ); + +/** + * Get the total number of entries in the hash table. + * + * @param ht the hash table. + * + * @return the number of entries in the hash table. + */ +PJ_DECL(unsigned) pj_hash_count( pj_hash_table_t *ht ); + + +/** + * Get the iterator to the first element in the hash table. + * + * @param ht the hash table. + * @param it the iterator for iterating hash elements. + * + * @return the iterator to the hash element, or NULL if no element presents. + */ +PJ_DECL(pj_hash_iterator_t*) pj_hash_first( pj_hash_table_t *ht, + pj_hash_iterator_t *it ); + + +/** + * Get the next element from the iterator. + * + * @param ht the hash table. + * @param it the hash iterator. + * + * @return the next iterator, or NULL if there's no more element. + */ +PJ_DECL(pj_hash_iterator_t*) pj_hash_next( pj_hash_table_t *ht, + pj_hash_iterator_t *it ); + +/** + * Get the value associated with a hash iterator. + * + * @param ht the hash table. + * @param it the hash iterator. + * + * @return the value associated with the current element in iterator. + */ +PJ_DECL(void*) pj_hash_this( pj_hash_table_t *ht, + pj_hash_iterator_t *it ); + + +/** + * @} + */ + +PJ_END_DECL + +#endif + + diff --git a/pjlib/include/pj/ioqueue.h b/pjlib/include/pj/ioqueue.h index 4262ac7e..cf83e9df 100644 --- a/pjlib/include/pj/ioqueue.h +++ b/pjlib/include/pj/ioqueue.h @@ -1,473 +1,473 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/ioqueue.h 10 10/29/05 11:29a Bennylp $ */ - -#ifndef __PJ_IOQUEUE_H__ -#define __PJ_IOQUEUE_H__ - -/** - * @file ioqueue.h - * @brief I/O Dispatching Mechanism - */ - -#include - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_IO Network I/O - * @brief Network I/O - * @ingroup PJ_OS - * - * This section contains API building blocks to perform network I/O and - * communications. If provides: - * - @ref PJ_SOCK - *\n - * A highly portable socket abstraction, runs on all kind of - * network APIs such as standard BSD socket, Windows socket, Linux - * \b kernel socket, PalmOS networking API, etc. - * - * - @ref pj_addr_resolve - *\n - * Portable address resolution, which implements #pj_gethostbyname(). - * - * - @ref PJ_SOCK_SELECT - *\n - * A portable \a select() like API (#pj_sock_select()) which can be - * implemented with various back-ends. - * - * - @ref PJ_IOQUEUE - *\n - * Framework for dispatching network events. - * - * For more information see the modules below. - */ - -/** - * @defgroup PJ_IOQUEUE I/O Event Dispatching Queue - * @ingroup PJ_IO - * @{ - * - * This file provides abstraction for various event dispatching mechanisms. - * The interfaces for event dispatching vary alot, even in a single - * operating system. The abstraction here hopefully is suitable for most of - * the event dispatching available. - * - * Currently, the I/O Queue supports: - * - select(), as the common denominator, but the least efficient. - * - I/O Completion ports in Windows NT/2000/XP, which is the most efficient - * way to dispatch events in Windows NT based OSes, and most importantly, - * it doesn't have the limit on how many handles to monitor. And it works - * with files (not only sockets) as well. - * - * \section pj_ioqeuue_examples_sec Examples - * - * For some examples on how to use the I/O Queue, please see: - * - * - \ref page_pjlib_ioqueue_tcp_test - * - \ref page_pjlib_ioqueue_udp_test - * - \ref page_pjlib_ioqueue_perf_test - */ - - /** - * This structure describes the callbacks to be called when I/O operation - * completes. - */ -typedef struct pj_ioqueue_callback -{ - /** - * This callback is called when #pj_ioqueue_read or #pj_ioqueue_recvfrom - * completes. - * - * @param key The key. - * @param bytes_read The size of data that has just been read. - */ - void (*on_read_complete)(pj_ioqueue_key_t *key, pj_ssize_t bytes_read); - - /** - * This callback is called when #pj_ioqueue_write or #pj_ioqueue_sendto - * completes. - * - * @param key The key. - * @param bytes_read The size of data that has just been read. - */ - void (*on_write_complete)(pj_ioqueue_key_t *key, pj_ssize_t bytes_sent); - - /** - * This callback is called when #pj_ioqueue_accept completes. - * - * @param key The key. - * @param sock Newly connected socket. - * @param status Zero if the operation completes successfully. - */ - void (*on_accept_complete)(pj_ioqueue_key_t *key, pj_sock_t sock, - int status); - - /** - * This callback is called when #pj_ioqueue_connect completes. - * - * @param key The key. - * @param status Zero if the operation completes successfully. - */ - void (*on_connect_complete)(pj_ioqueue_key_t *key, int status); -} pj_ioqueue_callback; - - -/** - * Types of I/O Queue operation. - */ -typedef enum pj_ioqueue_operation_e -{ - PJ_IOQUEUE_OP_NONE = 0, /**< No operation. */ - PJ_IOQUEUE_OP_READ = 1, /**< read() operation. */ - PJ_IOQUEUE_OP_RECV = 2, /**< recv() operation. */ - PJ_IOQUEUE_OP_RECV_FROM = 4, /**< recvfrom() operation. */ - PJ_IOQUEUE_OP_WRITE = 8, /**< write() operation. */ - PJ_IOQUEUE_OP_SEND = 16, /**< send() operation. */ - PJ_IOQUEUE_OP_SEND_TO = 32, /**< sendto() operation. */ -#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 - PJ_IOQUEUE_OP_ACCEPT = 64, /**< accept() operation. */ - PJ_IOQUEUE_OP_CONNECT = 128, /**< connect() operation. */ -#endif /* PJ_HAS_TCP */ -} pj_ioqueue_operation_e; - - -/** - * Indicates that the I/O Queue should be created to handle reasonable - * number of threads. - */ -#define PJ_IOQUEUE_DEFAULT_THREADS 0 - - -/** - * Create a new I/O Queue framework. - * - * @param pool The pool to allocate the I/O queue structure. - * @param max_fd The maximum number of handles to be supported, which - * should not exceed PJ_IOQUEUE_MAX_HANDLES. - * @param max_threads The maximum number of threads that are allowed to - * operate on a single descriptor simultaneously. If - * the value is zero, the framework will set it - * to a reasonable value. - * @param ioqueue Pointer to hold the newly created I/O Queue. - * - * @return PJ_SUCCESS on success. - */ -PJ_DECL(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, - pj_size_t max_fd, - int max_threads, - pj_ioqueue_t **ioqueue); - -/** - * Destroy the I/O queue. - * - * @param ioque The I/O Queue to be destroyed. - * - * @return PJ_SUCCESS if success. - */ -PJ_DECL(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioque ); - -/** - * Set the lock object to be used by the I/O Queue. This function can only - * be called right after the I/O queue is created, before any handle is - * registered to the I/O queue. - * - * Initially the I/O queue is created with non-recursive mutex protection. - * Applications can supply alternative lock to be used by calling this - * function. - * - * @param ioque The ioqueue instance. - * @param lock The lock to be used by the ioqueue. - * @param auto_delete In non-zero, the lock will be deleted by the ioqueue. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, - pj_lock_t *lock, - pj_bool_t auto_delete ); - -/** - * Register a socket to the I/O queue framework. - * When a socket is registered to the IOQueue, it may be modified to use - * non-blocking IO. If it is modified, there is no guarantee that this - * modification will be restored after the socket is unregistered. - * - * @param pool To allocate the resource for the specified handle, - * which must be valid until the handle/key is unregistered - * from I/O Queue. - * @param ioque The I/O Queue. - * @param sock The socket. - * @param user_data User data to be associated with the key, which can be - * retrieved later. - * @param cb Callback to be called when I/O operation completes. - * @param key Pointer to receive the returned key. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool, - pj_ioqueue_t *ioque, - pj_sock_t sock, - void *user_data, - const pj_ioqueue_callback *cb, - pj_ioqueue_key_t **key); - -/** - * Unregister a handle from the I/O Queue framework. - * - * @param ioque The I/O Queue. - * @param key The key that uniquely identifies the handle, which is - * returned from the function #pj_ioqueue_register_sock() - * or other registration functions. - * - * @return PJ_SUCCESS on success or the error code. - */ -PJ_DECL(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key ); - - -/** - * Get user data associated with the I/O Queue key. - * - * @param key The key previously associated with the socket/handle with - * #pj_ioqueue_register_sock() (or other registration - * functions). - * - * @return The user data associated with the key, or NULL on error - * of if no data is associated with the key during - * registration. - */ -PJ_DECL(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key ); - - -#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 -/** - * Instruct I/O Queue to wait for incoming connections on the specified - * listening socket. This function will return - * immediately (i.e. non-blocking) regardless whether some data has been - * transfered. If the function can't complete immediately, and the caller will - * be notified about the completion when it calls pj_ioqueue_poll(). - * - * @param ioqueue The I/O Queue - * @param key The key which registered to the server socket. - * @param sock Argument which contain pointer to receive - * the socket for the incoming connection. - * @param local Optional argument which contain pointer to variable to - * receive local address. - * @param remote Optional argument which contain pointer to variable to - * receive the remote address. - * @param addrlen On input, contains the length of the buffer for the - * address, and on output, contains the actual length of the - * address. This argument is optional. - * @return - * - PJ_SUCCESS If there's a connection available immediately, which - * in this case the callback should have been called before - * the function returns. - * - PJ_EPENDING If accept is queued, or - * - non-zero which indicates the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_ioqueue_accept( pj_ioqueue_t *ioqueue, - pj_ioqueue_key_t *key, - pj_sock_t *sock, - pj_sockaddr_t *local, - pj_sockaddr_t *remote, - int *addrlen ); - -/** - * Initiate non-blocking socket connect. If the socket can NOT be connected - * immediately, the result will be reported during poll. - * - * @param ioqueue The ioqueue - * @param key The key associated with TCP socket - * @param addr The remote address. - * @param addrlen The remote address length. - * - * @return - * - PJ_SUCCESS If socket is connected immediately, which in this case - * the callback should have been called. - * - PJ_EPENDING If operation is queued, or - * - non-zero Indicates the error code. - */ -PJ_DECL(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue, - pj_ioqueue_key_t *key, - const pj_sockaddr_t *addr, - int addrlen ); - -#endif /* PJ_HAS_TCP */ - -/** - * Poll the I/O Queue for completed events. - * - * @param ioque the I/O Queue. - * @param timeout polling timeout, or NULL if the thread wishes to wait - * indefinetely for the event. - * - * @return - * - zero if timed out (no event). - * - (<0) if error occured during polling. Callback will NOT be called. - * - (>1) to indicate numbers of events. Callbacks have been called. - */ -PJ_DECL(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, - const pj_time_val *timeout); - -/** - * Instruct the I/O Queue to read from the specified handle. This function - * returns immediately (i.e. non-blocking) regardless whether some data has - * been transfered. If the operation can't complete immediately, caller will - * be notified about the completion when it calls pj_ioqueue_poll(). - * - * @param ioque The I/O Queue. - * @param key The key that uniquely identifies the handle. - * @param buffer The buffer to hold the read data. The caller MUST make sure - * that this buffer remain valid until the framework completes - * reading the handle. - * @param buflen The maximum size to be read. - * - * @return - * - PJ_SUCCESS If immediate data has been received. In this case, the - * callback must have been called before this function - * returns, and no pending operation is scheduled. - * - PJ_EPENDING If the operation has been queued. - * - non-zero The return value indicates the error code. - */ -PJ_DECL(pj_status_t) pj_ioqueue_read( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - void *buffer, - pj_size_t buflen); - - -/** - * This function behaves similarly as #pj_ioqueue_read(), except that it is - * normally called for socket. - * - * @param ioque The I/O Queue. - * @param key The key that uniquely identifies the handle. - * @param buffer The buffer to hold the read data. The caller MUST make sure - * that this buffer remain valid until the framework completes - * reading the handle. - * @param buflen The maximum size to be read. - * @param flags Recv flag. - * - * @return - * - PJ_SUCCESS If immediate data has been received. In this case, the - * callback must have been called before this function - * returns, and no pending operation is scheduled. - * - PJ_EPENDING If the operation has been queued. - * - non-zero The return value indicates the error code. - */ -PJ_DECL(pj_status_t) pj_ioqueue_recv( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - void *buffer, - pj_size_t buflen, - unsigned flags ); - -/** - * This function behaves similarly as #pj_ioqueue_read(), except that it is - * normally called for socket, and the remote address will also be returned - * along with the data. Caller MUST make sure that both buffer and addr - * remain valid until the framework completes reading the data. - * - * @param ioque The I/O Queue. - * @param key The key that uniquely identifies the handle. - * @param buffer The buffer to hold the read data. The caller MUST make sure - * that this buffer remain valid until the framework completes - * reading the handle. - * @param buflen The maximum size to be read. - * @param flags Recv flag. - * @param addr Pointer to buffer to receive the address, or NULL. - * @param addrlen On input, specifies the length of the address buffer. - * On output, it will be filled with the actual length of - * the address. - * - * @return - * - PJ_SUCCESS If immediate data has been received. In this case, the - * callback must have been called before this function - * returns, and no pending operation is scheduled. - * - PJ_EPENDING If the operation has been queued. - * - non-zero The return value indicates the error code. - */ -PJ_DECL(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - void *buffer, - pj_size_t buflen, - unsigned flags, - pj_sockaddr_t *addr, - int *addrlen); - -/** - * Instruct the I/O Queue to write to the handle. This function will return - * immediately (i.e. non-blocking) regardless whether some data has been - * transfered. If the function can't complete immediately, and the caller will - * be notified about the completion when it calls pj_ioqueue_poll(). - * - * @param ioque the I/O Queue. - * @param key the key that identifies the handle. - * @param data the data to send. Caller MUST make sure that this buffer - * remains valid until the write operation completes. - * @param datalen the length of the data. - * - * @return - * - PJ_SUCCESS If data was immediately written. - * - PJ_EPENDING If the operation has been queued. - * - non-zero The return value indicates the error code. - */ -PJ_DECL(pj_status_t) pj_ioqueue_write( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - const void *data, - pj_size_t datalen); - -/** - * This function behaves similarly as #pj_ioqueue_write(), except that - * pj_sock_send() (or equivalent) will be called to send the data. - * - * @param ioque the I/O Queue. - * @param key the key that identifies the handle. - * @param data the data to send. Caller MUST make sure that this buffer - * remains valid until the write operation completes. - * @param datalen the length of the data. - * @param flags send flags. - * - * @return - * - PJ_SUCCESS If data was immediately written. - * - PJ_EPENDING If the operation has been queued. - * - non-zero The return value indicates the error code. - */ -PJ_DECL(pj_status_t) pj_ioqueue_send( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - const void *data, - pj_size_t datalen, - unsigned flags ); - - -/** - * This function behaves similarly as #pj_ioqueue_write(), except that - * pj_sock_sendto() (or equivalent) will be called to send the data. - * - * @param ioque the I/O Queue. - * @param key the key that identifies the handle. - * @param data the data to send. Caller MUST make sure that this buffer - * remains valid until the write operation completes. - * @param datalen the length of the data. - * @param flags send flags. - * @param addr remote address. - * @param addrlen remote address length. - * - * @return - * - PJ_SUCCESS If data was immediately written. - * - PJ_EPENDING If the operation has been queued. - * - non-zero The return value indicates the error code. - */ -PJ_DECL(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - const void *data, - pj_size_t datalen, - unsigned flags, - const pj_sockaddr_t *addr, - int addrlen); - - -/** - * !} - */ - -PJ_END_DECL - -#endif /* __PJ_IOQUEUE_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/ioqueue.h 10 10/29/05 11:29a Bennylp $ */ + +#ifndef __PJ_IOQUEUE_H__ +#define __PJ_IOQUEUE_H__ + +/** + * @file ioqueue.h + * @brief I/O Dispatching Mechanism + */ + +#include + +PJ_BEGIN_DECL + +/** + * @defgroup PJ_IO Network I/O + * @brief Network I/O + * @ingroup PJ_OS + * + * This section contains API building blocks to perform network I/O and + * communications. If provides: + * - @ref PJ_SOCK + *\n + * A highly portable socket abstraction, runs on all kind of + * network APIs such as standard BSD socket, Windows socket, Linux + * \b kernel socket, PalmOS networking API, etc. + * + * - @ref pj_addr_resolve + *\n + * Portable address resolution, which implements #pj_gethostbyname(). + * + * - @ref PJ_SOCK_SELECT + *\n + * A portable \a select() like API (#pj_sock_select()) which can be + * implemented with various back-ends. + * + * - @ref PJ_IOQUEUE + *\n + * Framework for dispatching network events. + * + * For more information see the modules below. + */ + +/** + * @defgroup PJ_IOQUEUE I/O Event Dispatching Queue + * @ingroup PJ_IO + * @{ + * + * This file provides abstraction for various event dispatching mechanisms. + * The interfaces for event dispatching vary alot, even in a single + * operating system. The abstraction here hopefully is suitable for most of + * the event dispatching available. + * + * Currently, the I/O Queue supports: + * - select(), as the common denominator, but the least efficient. + * - I/O Completion ports in Windows NT/2000/XP, which is the most efficient + * way to dispatch events in Windows NT based OSes, and most importantly, + * it doesn't have the limit on how many handles to monitor. And it works + * with files (not only sockets) as well. + * + * \section pj_ioqeuue_examples_sec Examples + * + * For some examples on how to use the I/O Queue, please see: + * + * - \ref page_pjlib_ioqueue_tcp_test + * - \ref page_pjlib_ioqueue_udp_test + * - \ref page_pjlib_ioqueue_perf_test + */ + + /** + * This structure describes the callbacks to be called when I/O operation + * completes. + */ +typedef struct pj_ioqueue_callback +{ + /** + * This callback is called when #pj_ioqueue_read or #pj_ioqueue_recvfrom + * completes. + * + * @param key The key. + * @param bytes_read The size of data that has just been read. + */ + void (*on_read_complete)(pj_ioqueue_key_t *key, pj_ssize_t bytes_read); + + /** + * This callback is called when #pj_ioqueue_write or #pj_ioqueue_sendto + * completes. + * + * @param key The key. + * @param bytes_read The size of data that has just been read. + */ + void (*on_write_complete)(pj_ioqueue_key_t *key, pj_ssize_t bytes_sent); + + /** + * This callback is called when #pj_ioqueue_accept completes. + * + * @param key The key. + * @param sock Newly connected socket. + * @param status Zero if the operation completes successfully. + */ + void (*on_accept_complete)(pj_ioqueue_key_t *key, pj_sock_t sock, + int status); + + /** + * This callback is called when #pj_ioqueue_connect completes. + * + * @param key The key. + * @param status Zero if the operation completes successfully. + */ + void (*on_connect_complete)(pj_ioqueue_key_t *key, int status); +} pj_ioqueue_callback; + + +/** + * Types of I/O Queue operation. + */ +typedef enum pj_ioqueue_operation_e +{ + PJ_IOQUEUE_OP_NONE = 0, /**< No operation. */ + PJ_IOQUEUE_OP_READ = 1, /**< read() operation. */ + PJ_IOQUEUE_OP_RECV = 2, /**< recv() operation. */ + PJ_IOQUEUE_OP_RECV_FROM = 4, /**< recvfrom() operation. */ + PJ_IOQUEUE_OP_WRITE = 8, /**< write() operation. */ + PJ_IOQUEUE_OP_SEND = 16, /**< send() operation. */ + PJ_IOQUEUE_OP_SEND_TO = 32, /**< sendto() operation. */ +#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 + PJ_IOQUEUE_OP_ACCEPT = 64, /**< accept() operation. */ + PJ_IOQUEUE_OP_CONNECT = 128, /**< connect() operation. */ +#endif /* PJ_HAS_TCP */ +} pj_ioqueue_operation_e; + + +/** + * Indicates that the I/O Queue should be created to handle reasonable + * number of threads. + */ +#define PJ_IOQUEUE_DEFAULT_THREADS 0 + + +/** + * Create a new I/O Queue framework. + * + * @param pool The pool to allocate the I/O queue structure. + * @param max_fd The maximum number of handles to be supported, which + * should not exceed PJ_IOQUEUE_MAX_HANDLES. + * @param max_threads The maximum number of threads that are allowed to + * operate on a single descriptor simultaneously. If + * the value is zero, the framework will set it + * to a reasonable value. + * @param ioqueue Pointer to hold the newly created I/O Queue. + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, + pj_size_t max_fd, + int max_threads, + pj_ioqueue_t **ioqueue); + +/** + * Destroy the I/O queue. + * + * @param ioque The I/O Queue to be destroyed. + * + * @return PJ_SUCCESS if success. + */ +PJ_DECL(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioque ); + +/** + * Set the lock object to be used by the I/O Queue. This function can only + * be called right after the I/O queue is created, before any handle is + * registered to the I/O queue. + * + * Initially the I/O queue is created with non-recursive mutex protection. + * Applications can supply alternative lock to be used by calling this + * function. + * + * @param ioque The ioqueue instance. + * @param lock The lock to be used by the ioqueue. + * @param auto_delete In non-zero, the lock will be deleted by the ioqueue. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, + pj_lock_t *lock, + pj_bool_t auto_delete ); + +/** + * Register a socket to the I/O queue framework. + * When a socket is registered to the IOQueue, it may be modified to use + * non-blocking IO. If it is modified, there is no guarantee that this + * modification will be restored after the socket is unregistered. + * + * @param pool To allocate the resource for the specified handle, + * which must be valid until the handle/key is unregistered + * from I/O Queue. + * @param ioque The I/O Queue. + * @param sock The socket. + * @param user_data User data to be associated with the key, which can be + * retrieved later. + * @param cb Callback to be called when I/O operation completes. + * @param key Pointer to receive the returned key. + * + * @return PJ_SUCCESS on success, or the error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool, + pj_ioqueue_t *ioque, + pj_sock_t sock, + void *user_data, + const pj_ioqueue_callback *cb, + pj_ioqueue_key_t **key); + +/** + * Unregister a handle from the I/O Queue framework. + * + * @param ioque The I/O Queue. + * @param key The key that uniquely identifies the handle, which is + * returned from the function #pj_ioqueue_register_sock() + * or other registration functions. + * + * @return PJ_SUCCESS on success or the error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key ); + + +/** + * Get user data associated with the I/O Queue key. + * + * @param key The key previously associated with the socket/handle with + * #pj_ioqueue_register_sock() (or other registration + * functions). + * + * @return The user data associated with the key, or NULL on error + * of if no data is associated with the key during + * registration. + */ +PJ_DECL(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key ); + + +#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 +/** + * Instruct I/O Queue to wait for incoming connections on the specified + * listening socket. This function will return + * immediately (i.e. non-blocking) regardless whether some data has been + * transfered. If the function can't complete immediately, and the caller will + * be notified about the completion when it calls pj_ioqueue_poll(). + * + * @param ioqueue The I/O Queue + * @param key The key which registered to the server socket. + * @param sock Argument which contain pointer to receive + * the socket for the incoming connection. + * @param local Optional argument which contain pointer to variable to + * receive local address. + * @param remote Optional argument which contain pointer to variable to + * receive the remote address. + * @param addrlen On input, contains the length of the buffer for the + * address, and on output, contains the actual length of the + * address. This argument is optional. + * @return + * - PJ_SUCCESS If there's a connection available immediately, which + * in this case the callback should have been called before + * the function returns. + * - PJ_EPENDING If accept is queued, or + * - non-zero which indicates the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_accept( pj_ioqueue_t *ioqueue, + pj_ioqueue_key_t *key, + pj_sock_t *sock, + pj_sockaddr_t *local, + pj_sockaddr_t *remote, + int *addrlen ); + +/** + * Initiate non-blocking socket connect. If the socket can NOT be connected + * immediately, the result will be reported during poll. + * + * @param ioqueue The ioqueue + * @param key The key associated with TCP socket + * @param addr The remote address. + * @param addrlen The remote address length. + * + * @return + * - PJ_SUCCESS If socket is connected immediately, which in this case + * the callback should have been called. + * - PJ_EPENDING If operation is queued, or + * - non-zero Indicates the error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue, + pj_ioqueue_key_t *key, + const pj_sockaddr_t *addr, + int addrlen ); + +#endif /* PJ_HAS_TCP */ + +/** + * Poll the I/O Queue for completed events. + * + * @param ioque the I/O Queue. + * @param timeout polling timeout, or NULL if the thread wishes to wait + * indefinetely for the event. + * + * @return + * - zero if timed out (no event). + * - (<0) if error occured during polling. Callback will NOT be called. + * - (>1) to indicate numbers of events. Callbacks have been called. + */ +PJ_DECL(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, + const pj_time_val *timeout); + +/** + * Instruct the I/O Queue to read from the specified handle. This function + * returns immediately (i.e. non-blocking) regardless whether some data has + * been transfered. If the operation can't complete immediately, caller will + * be notified about the completion when it calls pj_ioqueue_poll(). + * + * @param ioque The I/O Queue. + * @param key The key that uniquely identifies the handle. + * @param buffer The buffer to hold the read data. The caller MUST make sure + * that this buffer remain valid until the framework completes + * reading the handle. + * @param buflen The maximum size to be read. + * + * @return + * - PJ_SUCCESS If immediate data has been received. In this case, the + * callback must have been called before this function + * returns, and no pending operation is scheduled. + * - PJ_EPENDING If the operation has been queued. + * - non-zero The return value indicates the error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_read( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + void *buffer, + pj_size_t buflen); + + +/** + * This function behaves similarly as #pj_ioqueue_read(), except that it is + * normally called for socket. + * + * @param ioque The I/O Queue. + * @param key The key that uniquely identifies the handle. + * @param buffer The buffer to hold the read data. The caller MUST make sure + * that this buffer remain valid until the framework completes + * reading the handle. + * @param buflen The maximum size to be read. + * @param flags Recv flag. + * + * @return + * - PJ_SUCCESS If immediate data has been received. In this case, the + * callback must have been called before this function + * returns, and no pending operation is scheduled. + * - PJ_EPENDING If the operation has been queued. + * - non-zero The return value indicates the error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_recv( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + void *buffer, + pj_size_t buflen, + unsigned flags ); + +/** + * This function behaves similarly as #pj_ioqueue_read(), except that it is + * normally called for socket, and the remote address will also be returned + * along with the data. Caller MUST make sure that both buffer and addr + * remain valid until the framework completes reading the data. + * + * @param ioque The I/O Queue. + * @param key The key that uniquely identifies the handle. + * @param buffer The buffer to hold the read data. The caller MUST make sure + * that this buffer remain valid until the framework completes + * reading the handle. + * @param buflen The maximum size to be read. + * @param flags Recv flag. + * @param addr Pointer to buffer to receive the address, or NULL. + * @param addrlen On input, specifies the length of the address buffer. + * On output, it will be filled with the actual length of + * the address. + * + * @return + * - PJ_SUCCESS If immediate data has been received. In this case, the + * callback must have been called before this function + * returns, and no pending operation is scheduled. + * - PJ_EPENDING If the operation has been queued. + * - non-zero The return value indicates the error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + void *buffer, + pj_size_t buflen, + unsigned flags, + pj_sockaddr_t *addr, + int *addrlen); + +/** + * Instruct the I/O Queue to write to the handle. This function will return + * immediately (i.e. non-blocking) regardless whether some data has been + * transfered. If the function can't complete immediately, and the caller will + * be notified about the completion when it calls pj_ioqueue_poll(). + * + * @param ioque the I/O Queue. + * @param key the key that identifies the handle. + * @param data the data to send. Caller MUST make sure that this buffer + * remains valid until the write operation completes. + * @param datalen the length of the data. + * + * @return + * - PJ_SUCCESS If data was immediately written. + * - PJ_EPENDING If the operation has been queued. + * - non-zero The return value indicates the error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_write( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + const void *data, + pj_size_t datalen); + +/** + * This function behaves similarly as #pj_ioqueue_write(), except that + * pj_sock_send() (or equivalent) will be called to send the data. + * + * @param ioque the I/O Queue. + * @param key the key that identifies the handle. + * @param data the data to send. Caller MUST make sure that this buffer + * remains valid until the write operation completes. + * @param datalen the length of the data. + * @param flags send flags. + * + * @return + * - PJ_SUCCESS If data was immediately written. + * - PJ_EPENDING If the operation has been queued. + * - non-zero The return value indicates the error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_send( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + const void *data, + pj_size_t datalen, + unsigned flags ); + + +/** + * This function behaves similarly as #pj_ioqueue_write(), except that + * pj_sock_sendto() (or equivalent) will be called to send the data. + * + * @param ioque the I/O Queue. + * @param key the key that identifies the handle. + * @param data the data to send. Caller MUST make sure that this buffer + * remains valid until the write operation completes. + * @param datalen the length of the data. + * @param flags send flags. + * @param addr remote address. + * @param addrlen remote address length. + * + * @return + * - PJ_SUCCESS If data was immediately written. + * - PJ_EPENDING If the operation has been queued. + * - non-zero The return value indicates the error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + const void *data, + pj_size_t datalen, + unsigned flags, + const pj_sockaddr_t *addr, + int addrlen); + + +/** + * !} + */ + +PJ_END_DECL + +#endif /* __PJ_IOQUEUE_H__ */ + diff --git a/pjlib/include/pj/list.h b/pjlib/include/pj/list.h index 0b18f89c..dc7e5c6c 100644 --- a/pjlib/include/pj/list.h +++ b/pjlib/include/pj/list.h @@ -1,217 +1,217 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/list.h 8 10/14/05 12:26a Bennylp $ */ - -#ifndef __PJ_LIST_H__ -#define __PJ_LIST_H__ - -/** - * @file list.h - * @brief Linked List data structure. - */ - -#include - -PJ_BEGIN_DECL - -/* - * @defgroup PJ_DS Data Structure. - * @ingroup PJ - */ - -/** - * @defgroup PJ_LIST Linked List - * @ingroup PJ_DS - * @{ - * - * List in PJLIB is implemented as doubly-linked list, and it won't require - * dynamic memory allocation (just as all PJLIB data structures). The list here - * should be viewed more like a low level C list instead of high level C++ list - * (which normally are easier to use but require dynamic memory allocations), - * therefore all caveats with C list apply here too (such as you can NOT put - * a node in more than one lists). - * - * \section pj_list_example_sec Examples - * - * See below for examples on how to manipulate linked list: - * - @ref page_pjlib_samples_list_c - * - @ref page_pjlib_list_test - */ - - -/** - * Use this macro in the start of the structure declaration to declare that - * the structure can be used in the linked list operation. This macro simply - * declares additional member @a prev and @a next to the structure. - * @hideinitializer - */ -#define PJ_DECL_LIST_MEMBER(type) type *prev; /** List @a prev. */ \ - type *next; /** List @a next. */ - - -/** - * This structure describes generic list node and list. The owner of this list - * must initialize the 'value' member to an appropriate value (typically the - * owner itself). - */ -struct pj_list -{ - PJ_DECL_LIST_MEMBER(void) -}; - - -/** - * Initialize the list. - * Initially, the list will have no member, and function pj_list_empty() will - * always return nonzero (which indicates TRUE) for the newly initialized - * list. - * - * @param node The list head. - */ -PJ_INLINE(void) pj_list_init(pj_list_type * node) -{ - ((pj_list*)node)->next = ((pj_list*)node)->prev = node; -} - - -/** - * Check that the list is empty. - * - * @param node The list head. - * - * @return Non-zero if the list is not-empty, or zero if it is empty. - * - */ -PJ_INLINE(int) pj_list_empty(const pj_list_type * node) -{ - return ((pj_list*)node)->next == node; -} - - -/** - * Insert the node to the list before the specified element position. - * - * @param pos The element to which the node will be inserted before. - * @param node The element to be inserted. - * - * @return void. - */ -PJ_IDECL(void) pj_list_insert_before(pj_list_type *pos, pj_list_type *node); - - -/** - * Inserts all nodes in \a nodes to the target list. - * - * @param lst The target list. - * @param nodes Nodes list. - */ -PJ_IDECL(void) pj_list_insert_nodes_before(pj_list_type *lst, - pj_list_type *nodes); - -/** - * Insert a node to the list after the specified element position. - * - * @param pos The element in the list which will precede the inserted - * element. - * @param node The element to be inserted after the position element. - * - * @return void. - */ -PJ_IDECL(void) pj_list_insert_after(pj_list_type *pos, pj_list_type *node); - -/** - * Insert all nodes in \a nodes to the target list. - * - * @param lst The target list. - * @param nodes Nodes list. - */ -PJ_IDECL(void) pj_list_insert_nodes_after(pj_list_type *lst, - pj_list_type *nodes); - - -/** - * Remove elements from the source list, and insert them to the destination - * list. The elements of the source list will occupy the - * front elements of the target list. Note that the node pointed by \a list2 - * itself is not considered as a node, but rather as the list descriptor, so - * it will not be inserted to the \a list1. The elements to be inserted starts - * at \a list2->next. If \a list2 is to be included in the operation, use - * \a pj_list_insert_nodes_before. - * - * @param list1 The destination list. - * @param list2 The source list. - * - * @return void. - */ -PJ_IDECL(void) pj_list_merge_first(pj_list_type *list1, pj_list_type *list2); - - -/** - * Remove elements from the second list argument, and insert them to the list - * in the first argument. The elements from the second list will be appended - * to the first list. Note that the node pointed by \a list2 - * itself is not considered as a node, but rather as the list descriptor, so - * it will not be inserted to the \a list1. The elements to be inserted starts - * at \a list2->next. If \a list2 is to be included in the operation, use - * \a pj_list_insert_nodes_before. - * - * @param list1 The element in the list which will precede the inserted - * element. - * @param list2 The element in the list to be inserted. - * - * @return void. - */ -PJ_IDECL(void) pj_list_merge_last( pj_list_type *list1, pj_list_type *list2); - - -/** - * Erase the node from the list it currently belongs. - * - * @param node The element to be erased. - */ -PJ_IDECL(void) pj_list_erase(pj_list_type *node); - - -/** - * Find node in the list. - * - * @param list The list head. - * @param node The node element to be searched. - * - * @return The node itself if it is found in the list, or NULL if it is not - * found in the list. - */ -PJ_IDECL(pj_list_type*) pj_list_find_node(pj_list_type *list, - pj_list_type *node); - - -/** - * Search the list for the specified value, using the specified comparison - * function. This function iterates on nodes in the list, started with the - * first node, and call the user supplied comparison function until the - * comparison function returns ZERO. - * - * @param list The list head. - * @param value The user defined value to be passed in the comparison - * function - * @param comp The comparison function, which should return ZERO to - * indicate that the searched value is found. - * - * @return The first node that matched, or NULL if it is not found. - */ -PJ_IDECL(pj_list_type*) pj_list_search(pj_list_type *list, void *value, - int (*comp)(void *value, - const pj_list_type *node) - ); - - -/** - * @} - */ - -#if PJ_FUNCTIONS_ARE_INLINED -# include "list_i.h" -#endif - -PJ_END_DECL - -#endif /* __PJ_LIST_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/list.h 8 10/14/05 12:26a Bennylp $ */ + +#ifndef __PJ_LIST_H__ +#define __PJ_LIST_H__ + +/** + * @file list.h + * @brief Linked List data structure. + */ + +#include + +PJ_BEGIN_DECL + +/* + * @defgroup PJ_DS Data Structure. + * @ingroup PJ + */ + +/** + * @defgroup PJ_LIST Linked List + * @ingroup PJ_DS + * @{ + * + * List in PJLIB is implemented as doubly-linked list, and it won't require + * dynamic memory allocation (just as all PJLIB data structures). The list here + * should be viewed more like a low level C list instead of high level C++ list + * (which normally are easier to use but require dynamic memory allocations), + * therefore all caveats with C list apply here too (such as you can NOT put + * a node in more than one lists). + * + * \section pj_list_example_sec Examples + * + * See below for examples on how to manipulate linked list: + * - @ref page_pjlib_samples_list_c + * - @ref page_pjlib_list_test + */ + + +/** + * Use this macro in the start of the structure declaration to declare that + * the structure can be used in the linked list operation. This macro simply + * declares additional member @a prev and @a next to the structure. + * @hideinitializer + */ +#define PJ_DECL_LIST_MEMBER(type) type *prev; /** List @a prev. */ \ + type *next; /** List @a next. */ + + +/** + * This structure describes generic list node and list. The owner of this list + * must initialize the 'value' member to an appropriate value (typically the + * owner itself). + */ +struct pj_list +{ + PJ_DECL_LIST_MEMBER(void) +}; + + +/** + * Initialize the list. + * Initially, the list will have no member, and function pj_list_empty() will + * always return nonzero (which indicates TRUE) for the newly initialized + * list. + * + * @param node The list head. + */ +PJ_INLINE(void) pj_list_init(pj_list_type * node) +{ + ((pj_list*)node)->next = ((pj_list*)node)->prev = node; +} + + +/** + * Check that the list is empty. + * + * @param node The list head. + * + * @return Non-zero if the list is not-empty, or zero if it is empty. + * + */ +PJ_INLINE(int) pj_list_empty(const pj_list_type * node) +{ + return ((pj_list*)node)->next == node; +} + + +/** + * Insert the node to the list before the specified element position. + * + * @param pos The element to which the node will be inserted before. + * @param node The element to be inserted. + * + * @return void. + */ +PJ_IDECL(void) pj_list_insert_before(pj_list_type *pos, pj_list_type *node); + + +/** + * Inserts all nodes in \a nodes to the target list. + * + * @param lst The target list. + * @param nodes Nodes list. + */ +PJ_IDECL(void) pj_list_insert_nodes_before(pj_list_type *lst, + pj_list_type *nodes); + +/** + * Insert a node to the list after the specified element position. + * + * @param pos The element in the list which will precede the inserted + * element. + * @param node The element to be inserted after the position element. + * + * @return void. + */ +PJ_IDECL(void) pj_list_insert_after(pj_list_type *pos, pj_list_type *node); + +/** + * Insert all nodes in \a nodes to the target list. + * + * @param lst The target list. + * @param nodes Nodes list. + */ +PJ_IDECL(void) pj_list_insert_nodes_after(pj_list_type *lst, + pj_list_type *nodes); + + +/** + * Remove elements from the source list, and insert them to the destination + * list. The elements of the source list will occupy the + * front elements of the target list. Note that the node pointed by \a list2 + * itself is not considered as a node, but rather as the list descriptor, so + * it will not be inserted to the \a list1. The elements to be inserted starts + * at \a list2->next. If \a list2 is to be included in the operation, use + * \a pj_list_insert_nodes_before. + * + * @param list1 The destination list. + * @param list2 The source list. + * + * @return void. + */ +PJ_IDECL(void) pj_list_merge_first(pj_list_type *list1, pj_list_type *list2); + + +/** + * Remove elements from the second list argument, and insert them to the list + * in the first argument. The elements from the second list will be appended + * to the first list. Note that the node pointed by \a list2 + * itself is not considered as a node, but rather as the list descriptor, so + * it will not be inserted to the \a list1. The elements to be inserted starts + * at \a list2->next. If \a list2 is to be included in the operation, use + * \a pj_list_insert_nodes_before. + * + * @param list1 The element in the list which will precede the inserted + * element. + * @param list2 The element in the list to be inserted. + * + * @return void. + */ +PJ_IDECL(void) pj_list_merge_last( pj_list_type *list1, pj_list_type *list2); + + +/** + * Erase the node from the list it currently belongs. + * + * @param node The element to be erased. + */ +PJ_IDECL(void) pj_list_erase(pj_list_type *node); + + +/** + * Find node in the list. + * + * @param list The list head. + * @param node The node element to be searched. + * + * @return The node itself if it is found in the list, or NULL if it is not + * found in the list. + */ +PJ_IDECL(pj_list_type*) pj_list_find_node(pj_list_type *list, + pj_list_type *node); + + +/** + * Search the list for the specified value, using the specified comparison + * function. This function iterates on nodes in the list, started with the + * first node, and call the user supplied comparison function until the + * comparison function returns ZERO. + * + * @param list The list head. + * @param value The user defined value to be passed in the comparison + * function + * @param comp The comparison function, which should return ZERO to + * indicate that the searched value is found. + * + * @return The first node that matched, or NULL if it is not found. + */ +PJ_IDECL(pj_list_type*) pj_list_search(pj_list_type *list, void *value, + int (*comp)(void *value, + const pj_list_type *node) + ); + + +/** + * @} + */ + +#if PJ_FUNCTIONS_ARE_INLINED +# include "list_i.h" +#endif + +PJ_END_DECL + +#endif /* __PJ_LIST_H__ */ + diff --git a/pjlib/include/pj/list_i.h b/pjlib/include/pj/list_i.h index 5f995979..108a0b8e 100644 --- a/pjlib/include/pj/list_i.h +++ b/pjlib/include/pj/list_i.h @@ -1,101 +1,101 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/list_i.h 4 10/14/05 12:26a Bennylp $ */ - - -/* Internal */ -PJ_IDEF(void) pj_link_node(pj_list_type *prev, pj_list_type *next) -{ - ((pj_list*)prev)->next = next; - ((pj_list*)next)->prev = prev; -} - -/* -PJ_IDEF(void) -pj_list_init(pj_list_type * node) -{ - ((pj_list*)node)->next = ((pj_list*)node)->prev = node; -} - -PJ_IDEF(int) pj_list_empty(const pj_list_type * node) -{ - return ((pj_list*)node)->next == node; -} -*/ - -PJ_IDEF(void) -pj_list_insert_after(pj_list_type *pos, pj_list_type *node) -{ - ((pj_list*)node)->prev = pos; - ((pj_list*)node)->next = ((pj_list*)pos)->next; - ((pj_list*) ((pj_list*)pos)->next) ->prev = node; - ((pj_list*)pos)->next = node; -} - - -PJ_IDEF(void) -pj_list_insert_before(pj_list_type *pos, pj_list_type *node) -{ - pj_list_insert_after(((pj_list*)pos)->prev, node); -} - - -PJ_IDEF(void) -pj_list_insert_nodes_after(pj_list_type *pos, pj_list_type *lst) -{ - pj_list *lst_last = (pj_list *) ((pj_list*)lst)->prev; - pj_list *pos_next = (pj_list *) ((pj_list*)pos)->next; - - pj_link_node(pos, lst); - pj_link_node(lst_last, pos_next); -} - -PJ_IDEF(void) -pj_list_insert_nodes_before(pj_list_type *pos, pj_list_type *lst) -{ - pj_list_insert_nodes_after(((pj_list*)pos)->prev, lst); -} - -PJ_IDEF(void) -pj_list_merge_last(pj_list_type *lst1, pj_list_type *lst2) -{ - pj_link_node(((pj_list*)lst1)->prev, ((pj_list*)lst2)->next); - pj_link_node(((pj_list*)lst2)->prev, lst1); - pj_list_init(lst2); -} - -PJ_IDEF(void) -pj_list_merge_first(pj_list_type *lst1, pj_list_type *lst2) -{ - pj_link_node(((pj_list*)lst2)->prev, ((pj_list*)lst1)->next); - pj_link_node(((pj_list*)lst1), ((pj_list*)lst2)->next); - pj_list_init(lst2); -} - -PJ_IDEF(void) -pj_list_erase(pj_list_type *node) -{ - pj_link_node( ((pj_list*)node)->prev, ((pj_list*)node)->next); -} - - -PJ_IDEF(pj_list_type*) -pj_list_find_node(pj_list_type *list, pj_list_type *node) -{ - pj_list *p = (pj_list *) ((pj_list*)list)->next; - while (p != list && p != node) - p = (pj_list *) p->next; - - return p==node ? p : NULL; -} - - -PJ_IDEF(pj_list_type*) -pj_list_search(pj_list_type *list, void *value, - int (*comp)(void *value, const pj_list_type *node)) -{ - pj_list *p = (pj_list *) ((pj_list*)list)->next; - while (p != list && (*comp)(value, p) != 0) - p = (pj_list *) p->next; - - return p==list ? NULL : p; -} - +/* $Header: /pjproject-0.3/pjlib/include/pj/list_i.h 4 10/14/05 12:26a Bennylp $ */ + + +/* Internal */ +PJ_IDEF(void) pj_link_node(pj_list_type *prev, pj_list_type *next) +{ + ((pj_list*)prev)->next = next; + ((pj_list*)next)->prev = prev; +} + +/* +PJ_IDEF(void) +pj_list_init(pj_list_type * node) +{ + ((pj_list*)node)->next = ((pj_list*)node)->prev = node; +} + +PJ_IDEF(int) pj_list_empty(const pj_list_type * node) +{ + return ((pj_list*)node)->next == node; +} +*/ + +PJ_IDEF(void) +pj_list_insert_after(pj_list_type *pos, pj_list_type *node) +{ + ((pj_list*)node)->prev = pos; + ((pj_list*)node)->next = ((pj_list*)pos)->next; + ((pj_list*) ((pj_list*)pos)->next) ->prev = node; + ((pj_list*)pos)->next = node; +} + + +PJ_IDEF(void) +pj_list_insert_before(pj_list_type *pos, pj_list_type *node) +{ + pj_list_insert_after(((pj_list*)pos)->prev, node); +} + + +PJ_IDEF(void) +pj_list_insert_nodes_after(pj_list_type *pos, pj_list_type *lst) +{ + pj_list *lst_last = (pj_list *) ((pj_list*)lst)->prev; + pj_list *pos_next = (pj_list *) ((pj_list*)pos)->next; + + pj_link_node(pos, lst); + pj_link_node(lst_last, pos_next); +} + +PJ_IDEF(void) +pj_list_insert_nodes_before(pj_list_type *pos, pj_list_type *lst) +{ + pj_list_insert_nodes_after(((pj_list*)pos)->prev, lst); +} + +PJ_IDEF(void) +pj_list_merge_last(pj_list_type *lst1, pj_list_type *lst2) +{ + pj_link_node(((pj_list*)lst1)->prev, ((pj_list*)lst2)->next); + pj_link_node(((pj_list*)lst2)->prev, lst1); + pj_list_init(lst2); +} + +PJ_IDEF(void) +pj_list_merge_first(pj_list_type *lst1, pj_list_type *lst2) +{ + pj_link_node(((pj_list*)lst2)->prev, ((pj_list*)lst1)->next); + pj_link_node(((pj_list*)lst1), ((pj_list*)lst2)->next); + pj_list_init(lst2); +} + +PJ_IDEF(void) +pj_list_erase(pj_list_type *node) +{ + pj_link_node( ((pj_list*)node)->prev, ((pj_list*)node)->next); +} + + +PJ_IDEF(pj_list_type*) +pj_list_find_node(pj_list_type *list, pj_list_type *node) +{ + pj_list *p = (pj_list *) ((pj_list*)list)->next; + while (p != list && p != node) + p = (pj_list *) p->next; + + return p==node ? p : NULL; +} + + +PJ_IDEF(pj_list_type*) +pj_list_search(pj_list_type *list, void *value, + int (*comp)(void *value, const pj_list_type *node)) +{ + pj_list *p = (pj_list *) ((pj_list*)list)->next; + while (p != list && (*comp)(value, p) != 0) + p = (pj_list *) p->next; + + return p==list ? NULL : p; +} + diff --git a/pjlib/include/pj/lock.h b/pjlib/include/pj/lock.h index c487019a..26ee2e77 100644 --- a/pjlib/include/pj/lock.h +++ b/pjlib/include/pj/lock.h @@ -1,136 +1,136 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/lock.h 2 10/14/05 12:26a Bennylp $ */ -#ifndef __PJ_LOCK_H__ -#define __PJ_LOCK_H__ - -/** - * @file lock.h - * @brief Higher abstraction for locking objects. - */ -#include - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_LOCK Lock Objects - * @ingroup PJ_OS - * @{ - * - * Lock Objects are higher abstraction for different lock mechanisms. - * It offers the same API for manipulating different lock types (e.g. - * @ref PJ_MUTEX "mutex", @ref PJ_SEM "semaphores", or null locks). - * Because Lock Objects have the same API for different types of lock - * implementation, it can be passed around in function arguments. As the - * result, it can be used to control locking policy for a particular - * feature. - */ - - -/** - * Create simple, non recursive mutex lock object. - * - * @param pool Memory pool. - * @param name Lock object's name. - * @param lock Pointer to store the returned handle. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_lock_create_simple_mutex( pj_pool_t *pool, - const char *name, - pj_lock_t **lock ); - -/** - * Create recursive mutex lock object. - * - * @param pool Memory pool. - * @param name Lock object's name. - * @param lock Pointer to store the returned handle. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_lock_create_recursive_mutex( pj_pool_t *pool, - const char *name, - pj_lock_t **lock ); - - -/** - * Create NULL mutex. A NULL mutex doesn't actually have any synchronization - * object attached to it. - * - * @param pool Memory pool. - * @param name Lock object's name. - * @param lock Pointer to store the returned handle. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_lock_create_null_mutex( pj_pool_t *pool, - const char *name, - pj_lock_t **lock ); - - -#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 -/** - * Create semaphore lock object. - * - * @param pool Memory pool. - * @param name Lock object's name. - * @param initial Initial value of the semaphore. - * @param max Maximum value of the semaphore. - * @param lock Pointer to store the returned handle. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_lock_create_semaphore( pj_pool_t *pool, - const char *name, - unsigned initial, - unsigned max, - pj_lock_t **lock ); - -#endif /* PJ_HAS_SEMAPHORE */ - -/** - * Acquire lock on the specified lock object. - * - * @param lock The lock object. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_lock_acquire( pj_lock_t *lock ); - - -/** - * Try to acquire lock on the specified lock object. - * - * @param lock The lock object. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_lock_tryacquire( pj_lock_t *lock ); - - -/** - * Release lock on the specified lock object. - * - * @param lock The lock object. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_lock_release( pj_lock_t *lock ); - - -/** - * Destroy the lock object. - * - * @param lock The lock object. - * - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_lock_destroy( pj_lock_t *lock ); - - -/** @} */ - -PJ_END_DECL - - -#endif /* __PJ_LOCK_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/lock.h 2 10/14/05 12:26a Bennylp $ */ +#ifndef __PJ_LOCK_H__ +#define __PJ_LOCK_H__ + +/** + * @file lock.h + * @brief Higher abstraction for locking objects. + */ +#include + +PJ_BEGIN_DECL + +/** + * @defgroup PJ_LOCK Lock Objects + * @ingroup PJ_OS + * @{ + * + * Lock Objects are higher abstraction for different lock mechanisms. + * It offers the same API for manipulating different lock types (e.g. + * @ref PJ_MUTEX "mutex", @ref PJ_SEM "semaphores", or null locks). + * Because Lock Objects have the same API for different types of lock + * implementation, it can be passed around in function arguments. As the + * result, it can be used to control locking policy for a particular + * feature. + */ + + +/** + * Create simple, non recursive mutex lock object. + * + * @param pool Memory pool. + * @param name Lock object's name. + * @param lock Pointer to store the returned handle. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_lock_create_simple_mutex( pj_pool_t *pool, + const char *name, + pj_lock_t **lock ); + +/** + * Create recursive mutex lock object. + * + * @param pool Memory pool. + * @param name Lock object's name. + * @param lock Pointer to store the returned handle. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_lock_create_recursive_mutex( pj_pool_t *pool, + const char *name, + pj_lock_t **lock ); + + +/** + * Create NULL mutex. A NULL mutex doesn't actually have any synchronization + * object attached to it. + * + * @param pool Memory pool. + * @param name Lock object's name. + * @param lock Pointer to store the returned handle. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_lock_create_null_mutex( pj_pool_t *pool, + const char *name, + pj_lock_t **lock ); + + +#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 +/** + * Create semaphore lock object. + * + * @param pool Memory pool. + * @param name Lock object's name. + * @param initial Initial value of the semaphore. + * @param max Maximum value of the semaphore. + * @param lock Pointer to store the returned handle. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_lock_create_semaphore( pj_pool_t *pool, + const char *name, + unsigned initial, + unsigned max, + pj_lock_t **lock ); + +#endif /* PJ_HAS_SEMAPHORE */ + +/** + * Acquire lock on the specified lock object. + * + * @param lock The lock object. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_lock_acquire( pj_lock_t *lock ); + + +/** + * Try to acquire lock on the specified lock object. + * + * @param lock The lock object. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_lock_tryacquire( pj_lock_t *lock ); + + +/** + * Release lock on the specified lock object. + * + * @param lock The lock object. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_lock_release( pj_lock_t *lock ); + + +/** + * Destroy the lock object. + * + * @param lock The lock object. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_lock_destroy( pj_lock_t *lock ); + + +/** @} */ + +PJ_END_DECL + + +#endif /* __PJ_LOCK_H__ */ + diff --git a/pjlib/include/pj/log.h b/pjlib/include/pj/log.h index 5d24f56c..fb79a0e7 100644 --- a/pjlib/include/pj/log.h +++ b/pjlib/include/pj/log.h @@ -1,304 +1,304 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/log.h 7 10/14/05 12:26a Bennylp $ */ - -#ifndef __PJ_LOG_H__ -#define __PJ_LOG_H__ - -/** - * @file log.h - * @brief Logging Utility. - */ - -#include - - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_MISC Miscelaneous - * @ingroup PJ - */ - -/** - * @defgroup PJ_LOG Logging Facility - * @ingroup PJ_MISC - * @{ - * - * The PJLIB logging facility is a configurable, flexible, and convenient - * way to write logging or trace information. - * - * To write to the log, one uses construct like below: - * - *
- *   ...
- *   PJ_LOG(3, ("main.c", "Starting hello..."));
- *   ...
- *   PJ_LOG(3, ("main.c", "Hello world from process %d", pj_getpid()));
- *   ...
- * 
- * - * In the above example, the number @b 3 controls the verbosity level of - * the information (which means "information", by convention). The string - * "main.c" specifies the source or sender of the message. - * - * - * \section pj_log_quick_sample_sec Examples - * - * For examples, see: - * - @ref page_pjlib_samples_log_c. - * - */ - -/** - * Log decoration flag, to be specified with #pj_log_set_decor(). - */ -enum pj_log_decoration -{ - PJ_LOG_HAS_DAY_NAME = 1, /**< Include day name [default: no]. */ - PJ_LOG_HAS_YEAR = 2, /**< Include year digit [default: no] */ - PJ_LOG_HAS_MONTH = 4, /**< Include month [default: no] */ - PJ_LOG_HAS_DAY_OF_MON = 8, /**< Include day of month [default: no] */ - PJ_LOG_HAS_TIME = 16, /**< Include time [default: yes]. */ - PJ_LOG_HAS_MICRO_SEC = 32, /**< Include microseconds [yes] */ - PJ_LOG_HAS_SENDER = 64, /**< Include sender in the log [yes]. */ - PJ_LOG_HAS_NEWLINE = 128, /**< Terminate each call with newline [yes].*/ -}; - -/** - * Write log message. - * This is the main macro used to write text to the logging backend. - * - * @param level The logging verbosity level. Lower number indicates higher - * importance, with level zero indicates fatal error. Only - * numeral argument is permitted (e.g. not variable). - * @param arg Enclosed 'printf' like arguments, with the first - * argument is the sender, the second argument is format - * string and the following arguments are variable number of - * arguments suitable for the format string. - * - * Sample: - * \verbatim - PJ_LOG(2, (__FILE__, "current value is %d", value)); - \endverbatim - * @hideinitializer - */ -#define PJ_LOG(level,arg) pj_log_wrapper_##level(arg) - -/** - * Signature for function to be registered to the logging subsystem to - * write the actual log message to some output device. - * - * @param level Log level. - * @param data Log message. - * @param len Message length. - */ -typedef void pj_log_func(int level, const char *data, int len); - -/** - * Default logging writer function used by front end logger function. - * Application normally should NOT need to call this function, but - * rather use the PJ_LOG macro. - * - * @param level Log level. - * @param buffer Log message. - * @param len Message length. - */ -PJ_DECL(void) pj_log_write(int level, const char *buffer, int len); - - -#if PJ_LOG_MAX_LEVEL >= 1 - -/** - * Change log output function. The front-end logging functions will call - * this function to write the actual message to the desired device. - * By default, the front-end functions use pj_log_write() to write - * the messages, unless it's changed by calling this function. - * - * @param func The function that will be called to write the log - * messages to the desired device. - */ -PJ_DECL(void) pj_log_set_log_func( pj_log_func *func ); - -/** - * Get the current log output function that is used to write log messages. - * - * @return Current log output function. - */ -PJ_DECL(pj_log_func*) pj_log_get_log_func(void); - -/** - * Set maximum log level. Application can call this function to set - * the desired level of verbosity of the logging messages. The bigger the - * value, the more verbose the logging messages will be printed. However, - * the maximum level of verbosity can not exceed compile time value of - * PJ_LOG_MAX_LEVEL. - * - * @param level The maximum level of verbosity of the logging - * messages (6=very detailed..1=error only, 0=disabled) - */ -PJ_DECL(void) pj_log_set_level(int level); - -/** - * Get current maximum log verbositylevel. - * - * @return Current log maximum level. - */ -PJ_DECL(int) pj_log_get_level(void); - -/** - * Set log decoration. The log decoration flag controls what are printed - * to output device alongside the actual message. For example, application - * can specify that date/time information should be displayed with each - * log message. - * - * @param decor Bitmask combination of #pj_log_decoration to control - * the layout of the log message. - */ -PJ_DECL(void) pj_log_set_decor(unsigned decor); - -/** - * Get current log decoration flag. - * - * @return Log decoration flag. - */ -PJ_DECL(unsigned) pj_log_get_decor(void); - - -#else /* #if PJ_LOG_MAX_LEVEL >= 1 */ - -/** - * Change log output function. The front-end logging functions will call - * this function to write the actual message to the desired device. - * By default, the front-end functions use pj_log_write() to write - * the messages, unless it's changed by calling this function. - * - * @param func The function that will be called to write the log - * messages to the desired device. - */ -# define pj_log_set_log_func(func) - -/** - * Set maximum log level. Application can call this function to set - * the desired level of verbosity of the logging messages. The bigger the - * value, the more verbose the logging messages will be printed. However, - * the maximum level of verbosity can not exceed compile time value of - * PJ_LOG_MAX_LEVEL. - * - * @param level The maximum level of verbosity of the logging - * messages (6=very detailed..1=error only, 0=disabled) - */ -# define pj_log_set_level(level) - -/** - * Set log decoration. The log decoration flag controls what are printed - * to output device alongside the actual message. For example, application - * can specify that date/time information should be displayed with each - * log message. - * - * @param decor Bitmask combination of #pj_log_decoration to control - * the layout of the log message. - */ -# define pj_log_set_decor(decor) - -#endif /* #if PJ_LOG_MAX_LEVEL >= 1 */ - -/** - * @} - */ - -/////////////////////////////////////////////////////////////////////////////// -/* - * Log functions implementation prototypes. - * These functions are called by PJ_LOG macros according to verbosity - * level specified when calling the macro. Applications should not normally - * need to call these functions directly. - */ - -/** - * @def pj_log_wrapper_1(arg) - * Internal function to write log with verbosity 1. Will evaluate to - * empty expression if PJ_LOG_MAX_LEVEL is below 1. - * @param arg Log expression. - */ -#if PJ_LOG_MAX_LEVEL >= 1 - #define pj_log_wrapper_1(arg) pj_log_1 arg - /** Internal function. */ - PJ_DECL(void) pj_log_1(const char *src, const char *format, ...); -#else - #define pj_log_wrapper_1(arg) -#endif - -/** - * @def pj_log_wrapper_2(arg) - * Internal function to write log with verbosity 2. Will evaluate to - * empty expression if PJ_LOG_MAX_LEVEL is below 2. - * @param arg Log expression. - */ -#if PJ_LOG_MAX_LEVEL >= 2 - #define pj_log_wrapper_2(arg) pj_log_2 arg - /** Internal function. */ - PJ_DECL(void) pj_log_2(const char *src, const char *format, ...); -#else - #define pj_log_wrapper_2(arg) -#endif - -/** - * @def pj_log_wrapper_3(arg) - * Internal function to write log with verbosity 3. Will evaluate to - * empty expression if PJ_LOG_MAX_LEVEL is below 3. - * @param arg Log expression. - */ -#if PJ_LOG_MAX_LEVEL >= 3 - #define pj_log_wrapper_3(arg) pj_log_3 arg - /** Internal function. */ - PJ_DECL(void) pj_log_3(const char *src, const char *format, ...); -#else - #define pj_log_wrapper_3(arg) -#endif - -/** - * @def pj_log_wrapper_4(arg) - * Internal function to write log with verbosity 4. Will evaluate to - * empty expression if PJ_LOG_MAX_LEVEL is below 4. - * @param arg Log expression. - */ -#if PJ_LOG_MAX_LEVEL >= 4 - #define pj_log_wrapper_4(arg) pj_log_4 arg - /** Internal function. */ - PJ_DECL(void) pj_log_4(const char *src, const char *format, ...); -#else - #define pj_log_wrapper_4(arg) -#endif - -/** - * @def pj_log_wrapper_5(arg) - * Internal function to write log with verbosity 5. Will evaluate to - * empty expression if PJ_LOG_MAX_LEVEL is below 5. - * @param arg Log expression. - */ -#if PJ_LOG_MAX_LEVEL >= 5 - #define pj_log_wrapper_5(arg) pj_log_5 arg - /** Internal function. */ - PJ_DECL(void) pj_log_5(const char *src, const char *format, ...); -#else - #define pj_log_wrapper_5(arg) -#endif - -/** - * @def pj_log_wrapper_6(arg) - * Internal function to write log with verbosity 6. Will evaluate to - * empty expression if PJ_LOG_MAX_LEVEL is below 6. - * @param arg Log expression. - */ -#if PJ_LOG_MAX_LEVEL >= 6 - #define pj_log_wrapper_6(arg) pj_log_6 arg - /** Internal function. */ - PJ_DECL(void) pj_log_6(const char *src, const char *format, ...); -#else - #define pj_log_wrapper_6(arg) -#endif - - -PJ_END_DECL - -#endif /* __PJ_LOG_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/log.h 7 10/14/05 12:26a Bennylp $ */ + +#ifndef __PJ_LOG_H__ +#define __PJ_LOG_H__ + +/** + * @file log.h + * @brief Logging Utility. + */ + +#include + + +PJ_BEGIN_DECL + +/** + * @defgroup PJ_MISC Miscelaneous + * @ingroup PJ + */ + +/** + * @defgroup PJ_LOG Logging Facility + * @ingroup PJ_MISC + * @{ + * + * The PJLIB logging facility is a configurable, flexible, and convenient + * way to write logging or trace information. + * + * To write to the log, one uses construct like below: + * + *
+ *   ...
+ *   PJ_LOG(3, ("main.c", "Starting hello..."));
+ *   ...
+ *   PJ_LOG(3, ("main.c", "Hello world from process %d", pj_getpid()));
+ *   ...
+ * 
+ * + * In the above example, the number @b 3 controls the verbosity level of + * the information (which means "information", by convention). The string + * "main.c" specifies the source or sender of the message. + * + * + * \section pj_log_quick_sample_sec Examples + * + * For examples, see: + * - @ref page_pjlib_samples_log_c. + * + */ + +/** + * Log decoration flag, to be specified with #pj_log_set_decor(). + */ +enum pj_log_decoration +{ + PJ_LOG_HAS_DAY_NAME = 1, /**< Include day name [default: no]. */ + PJ_LOG_HAS_YEAR = 2, /**< Include year digit [default: no] */ + PJ_LOG_HAS_MONTH = 4, /**< Include month [default: no] */ + PJ_LOG_HAS_DAY_OF_MON = 8, /**< Include day of month [default: no] */ + PJ_LOG_HAS_TIME = 16, /**< Include time [default: yes]. */ + PJ_LOG_HAS_MICRO_SEC = 32, /**< Include microseconds [yes] */ + PJ_LOG_HAS_SENDER = 64, /**< Include sender in the log [yes]. */ + PJ_LOG_HAS_NEWLINE = 128, /**< Terminate each call with newline [yes].*/ +}; + +/** + * Write log message. + * This is the main macro used to write text to the logging backend. + * + * @param level The logging verbosity level. Lower number indicates higher + * importance, with level zero indicates fatal error. Only + * numeral argument is permitted (e.g. not variable). + * @param arg Enclosed 'printf' like arguments, with the first + * argument is the sender, the second argument is format + * string and the following arguments are variable number of + * arguments suitable for the format string. + * + * Sample: + * \verbatim + PJ_LOG(2, (__FILE__, "current value is %d", value)); + \endverbatim + * @hideinitializer + */ +#define PJ_LOG(level,arg) pj_log_wrapper_##level(arg) + +/** + * Signature for function to be registered to the logging subsystem to + * write the actual log message to some output device. + * + * @param level Log level. + * @param data Log message. + * @param len Message length. + */ +typedef void pj_log_func(int level, const char *data, int len); + +/** + * Default logging writer function used by front end logger function. + * Application normally should NOT need to call this function, but + * rather use the PJ_LOG macro. + * + * @param level Log level. + * @param buffer Log message. + * @param len Message length. + */ +PJ_DECL(void) pj_log_write(int level, const char *buffer, int len); + + +#if PJ_LOG_MAX_LEVEL >= 1 + +/** + * Change log output function. The front-end logging functions will call + * this function to write the actual message to the desired device. + * By default, the front-end functions use pj_log_write() to write + * the messages, unless it's changed by calling this function. + * + * @param func The function that will be called to write the log + * messages to the desired device. + */ +PJ_DECL(void) pj_log_set_log_func( pj_log_func *func ); + +/** + * Get the current log output function that is used to write log messages. + * + * @return Current log output function. + */ +PJ_DECL(pj_log_func*) pj_log_get_log_func(void); + +/** + * Set maximum log level. Application can call this function to set + * the desired level of verbosity of the logging messages. The bigger the + * value, the more verbose the logging messages will be printed. However, + * the maximum level of verbosity can not exceed compile time value of + * PJ_LOG_MAX_LEVEL. + * + * @param level The maximum level of verbosity of the logging + * messages (6=very detailed..1=error only, 0=disabled) + */ +PJ_DECL(void) pj_log_set_level(int level); + +/** + * Get current maximum log verbositylevel. + * + * @return Current log maximum level. + */ +PJ_DECL(int) pj_log_get_level(void); + +/** + * Set log decoration. The log decoration flag controls what are printed + * to output device alongside the actual message. For example, application + * can specify that date/time information should be displayed with each + * log message. + * + * @param decor Bitmask combination of #pj_log_decoration to control + * the layout of the log message. + */ +PJ_DECL(void) pj_log_set_decor(unsigned decor); + +/** + * Get current log decoration flag. + * + * @return Log decoration flag. + */ +PJ_DECL(unsigned) pj_log_get_decor(void); + + +#else /* #if PJ_LOG_MAX_LEVEL >= 1 */ + +/** + * Change log output function. The front-end logging functions will call + * this function to write the actual message to the desired device. + * By default, the front-end functions use pj_log_write() to write + * the messages, unless it's changed by calling this function. + * + * @param func The function that will be called to write the log + * messages to the desired device. + */ +# define pj_log_set_log_func(func) + +/** + * Set maximum log level. Application can call this function to set + * the desired level of verbosity of the logging messages. The bigger the + * value, the more verbose the logging messages will be printed. However, + * the maximum level of verbosity can not exceed compile time value of + * PJ_LOG_MAX_LEVEL. + * + * @param level The maximum level of verbosity of the logging + * messages (6=very detailed..1=error only, 0=disabled) + */ +# define pj_log_set_level(level) + +/** + * Set log decoration. The log decoration flag controls what are printed + * to output device alongside the actual message. For example, application + * can specify that date/time information should be displayed with each + * log message. + * + * @param decor Bitmask combination of #pj_log_decoration to control + * the layout of the log message. + */ +# define pj_log_set_decor(decor) + +#endif /* #if PJ_LOG_MAX_LEVEL >= 1 */ + +/** + * @} + */ + +/////////////////////////////////////////////////////////////////////////////// +/* + * Log functions implementation prototypes. + * These functions are called by PJ_LOG macros according to verbosity + * level specified when calling the macro. Applications should not normally + * need to call these functions directly. + */ + +/** + * @def pj_log_wrapper_1(arg) + * Internal function to write log with verbosity 1. Will evaluate to + * empty expression if PJ_LOG_MAX_LEVEL is below 1. + * @param arg Log expression. + */ +#if PJ_LOG_MAX_LEVEL >= 1 + #define pj_log_wrapper_1(arg) pj_log_1 arg + /** Internal function. */ + PJ_DECL(void) pj_log_1(const char *src, const char *format, ...); +#else + #define pj_log_wrapper_1(arg) +#endif + +/** + * @def pj_log_wrapper_2(arg) + * Internal function to write log with verbosity 2. Will evaluate to + * empty expression if PJ_LOG_MAX_LEVEL is below 2. + * @param arg Log expression. + */ +#if PJ_LOG_MAX_LEVEL >= 2 + #define pj_log_wrapper_2(arg) pj_log_2 arg + /** Internal function. */ + PJ_DECL(void) pj_log_2(const char *src, const char *format, ...); +#else + #define pj_log_wrapper_2(arg) +#endif + +/** + * @def pj_log_wrapper_3(arg) + * Internal function to write log with verbosity 3. Will evaluate to + * empty expression if PJ_LOG_MAX_LEVEL is below 3. + * @param arg Log expression. + */ +#if PJ_LOG_MAX_LEVEL >= 3 + #define pj_log_wrapper_3(arg) pj_log_3 arg + /** Internal function. */ + PJ_DECL(void) pj_log_3(const char *src, const char *format, ...); +#else + #define pj_log_wrapper_3(arg) +#endif + +/** + * @def pj_log_wrapper_4(arg) + * Internal function to write log with verbosity 4. Will evaluate to + * empty expression if PJ_LOG_MAX_LEVEL is below 4. + * @param arg Log expression. + */ +#if PJ_LOG_MAX_LEVEL >= 4 + #define pj_log_wrapper_4(arg) pj_log_4 arg + /** Internal function. */ + PJ_DECL(void) pj_log_4(const char *src, const char *format, ...); +#else + #define pj_log_wrapper_4(arg) +#endif + +/** + * @def pj_log_wrapper_5(arg) + * Internal function to write log with verbosity 5. Will evaluate to + * empty expression if PJ_LOG_MAX_LEVEL is below 5. + * @param arg Log expression. + */ +#if PJ_LOG_MAX_LEVEL >= 5 + #define pj_log_wrapper_5(arg) pj_log_5 arg + /** Internal function. */ + PJ_DECL(void) pj_log_5(const char *src, const char *format, ...); +#else + #define pj_log_wrapper_5(arg) +#endif + +/** + * @def pj_log_wrapper_6(arg) + * Internal function to write log with verbosity 6. Will evaluate to + * empty expression if PJ_LOG_MAX_LEVEL is below 6. + * @param arg Log expression. + */ +#if PJ_LOG_MAX_LEVEL >= 6 + #define pj_log_wrapper_6(arg) pj_log_6 arg + /** Internal function. */ + PJ_DECL(void) pj_log_6(const char *src, const char *format, ...); +#else + #define pj_log_wrapper_6(arg) +#endif + + +PJ_END_DECL + +#endif /* __PJ_LOG_H__ */ + diff --git a/pjlib/include/pj/md5.h b/pjlib/include/pj/md5.h index 979d8584..d3f93995 100644 --- a/pjlib/include/pj/md5.h +++ b/pjlib/include/pj/md5.h @@ -1,92 +1,92 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/md5.h 5 9/17/05 10:37a Bennylp $ */ -/* - Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.h is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Removed support for non-ANSI compilers; removed - references to Ghostscript; clarified derivation from RFC 1321; - now handles byte order either statically or dynamically. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); - added conditionalization for C++ compilation from Martin - Purschke . - 1999-05-03 lpd Original version. - */ - -#ifndef md5_INCLUDED -# define md5_INCLUDED - -/* - * This package supports both compile-time and run-time determination of CPU - * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be - * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is - * defined as non-zero, the code will be compiled to run only on big-endian - * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to - * run on either big- or little-endian CPUs, but will run slightly less - * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. - */ - -typedef unsigned char md5_byte_t; /* 8-bit byte */ -typedef unsigned long md5_word_t; /* 32-bit word */ - -/** Define the state of the MD5 Algorithm. */ -typedef struct md5_state_s { - md5_word_t count[2]; /**< message length in bits, lsw first */ - md5_word_t abcd[4]; /**< digest buffer */ - md5_byte_t buf[64]; /**< accumulate block */ -} md5_state_t; - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** Initialize the algorithm. */ -void md5_init(md5_state_t *pms); - -/** Append a string to the message. */ -void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); - -/** Finish the message and return the digest. */ -void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); - -#ifdef __cplusplus -} /* end extern "C" */ -#endif - -#endif /* md5_INCLUDED */ +/* $Header: /pjproject-0.3/pjlib/src/pj/md5.h 5 9/17/05 10:37a Bennylp $ */ +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. + */ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned long md5_word_t; /* 32-bit word */ + +/** Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /**< message length in bits, lsw first */ + md5_word_t abcd[4]; /**< digest buffer */ + md5_byte_t buf[64]; /**< accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** Initialize the algorithm. */ +void md5_init(md5_state_t *pms); + +/** Append a string to the message. */ +void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + +/** Finish the message and return the digest. */ +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* md5_INCLUDED */ diff --git a/pjlib/include/pj/os.h b/pjlib/include/pj/os.h index 845a26bc..f37ca702 100644 --- a/pjlib/include/pj/os.h +++ b/pjlib/include/pj/os.h @@ -1,904 +1,909 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/os.h 12 10/29/05 11:30a Bennylp $ */ - -#ifndef __PJ_OS_H__ -#define __PJ_OS_H__ - -/** - * @file os.h - * @brief OS dependent functions - */ -#include - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_OS Operating System Dependent Functionality. - * @ingroup PJ - */ - - -/////////////////////////////////////////////////////////////////////////////// -/** - * @defgroup PJ_THREAD Threads - * @ingroup PJ_OS - * @{ - * This module provides multithreading API. - * - * \section pj_thread_examples_sec Examples - * - * For examples, please see: - * - \ref page_pjlib_thread_test - * - \ref page_pjlib_sleep_test - * - */ - -/** - * Thread creation flags: - * - PJ_THREAD_SUSPENDED: specify that the thread should be created suspended. - */ -typedef enum pj_thread_create_flags -{ - PJ_THREAD_SUSPENDED = 1 -} pj_thread_create_flags; - - -/** - * Specify this as \a stack_size argument in #pj_thread_create() to specify - * that thread should use default stack size for the current platform. - */ -#define PJ_THREAD_DEFAULT_STACK_SIZE 0 - -/** - * Type of thread entry function. - */ -typedef int (PJ_THREAD_FUNC pj_thread_proc)(void*); - -/** - * Size of thread struct. - */ -#if !defined(PJ_THREAD_DESC_SIZE) -# define PJ_THREAD_DESC_SIZE (PJ_MAX_OBJ_NAME + 10*sizeof(long)) -#endif - -/** - * Thread structure, to thread's state when the thread is created by external - * or native API. - */ -typedef pj_uint8_t pj_thread_desc[PJ_THREAD_DESC_SIZE]; - -/** - * Get process ID. - * @return process ID. - */ -PJ_DECL(pj_uint32_t) pj_getpid(void); - -/** - * Create a new thread. - * - * @param pool The memory pool from which the thread record - * will be allocated from. - * @param thread_name The optional name to be assigned to the thread. - * @param proc Thread entry function. - * @param arg Argument to be passed to the thread entry function. - * @param stack_size The size of the stack for the new thread, or ZERO or - * PJ_THREAD_DEFAULT_STACK_SIZE to let the - * library choose the reasonable size for the stack. - * For some systems, the stack will be allocated from - * the pool, so the pool must have suitable capacity. - * @param flags Flags for thread creation, which is bitmask combination - * from enum pj_thread_create_flags. - * @param thread Pointer to hold the newly created thread. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_thread_create( pj_pool_t *pool, - const char *thread_name, - pj_thread_proc *proc, - void *arg, - pj_size_t stack_size, - unsigned flags, - pj_thread_t **thread ); - -/** - * Register a thread that was created by external or native API to PJLIB. - * This function must be called in the context of the thread being registered. - * When the thread is created by external function or API call, - * it must be 'registered' to PJLIB using pj_thread_register(), so that it can - * cooperate with PJLIB's framework. During registration, some data needs to - * be maintained, and this data must remain available during the thread's - * lifetime. - * - * @param thread_name The optional name to be assigned to the thread. - * @param desc Thread descriptor, which must be available throughout - * the lifetime of the thread. - * @param thread Pointer to hold the created thread handle. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_thread_register ( const char *thread_name, - pj_thread_desc desc, - pj_thread_t **thread); - -/** - * Get thread name. - * - * @param thread The thread handle. - * - * @return Thread name as null terminated string. - */ -PJ_DECL(const char*) pj_thread_get_name(pj_thread_t *thread); - -/** - * Resume a suspended thread. - * - * @param thread The thread handle. - * - * @return zero on success. - */ -PJ_DECL(pj_status_t) pj_thread_resume(pj_thread_t *thread); - -/** - * Get the current thread. - * - * @return Thread handle of current thread. - */ -PJ_DECL(pj_thread_t*) pj_thread_this(void); - -/** - * Join thread. - * This function will block the caller thread until the specified thread exits. - * - * @param thread The thread handle. - * - * @return zero on success. - */ -PJ_DECL(pj_status_t) pj_thread_join(pj_thread_t *thread); - - -/** - * Destroy thread and release resources allocated for the thread. - * However, the memory allocated for the pj_thread_t itself will only be released - * when the pool used to create the thread is destroyed. - * - * @param thread The thread handle. - * - * @return zero on success. - */ -PJ_DECL(pj_status_t) pj_thread_destroy(pj_thread_t *thread); - - -/** - * Put the current thread to sleep for the specified miliseconds. - * - * @param msec Miliseconds delay. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_thread_sleep(unsigned msec); - -/** - * @def PJ_CHECK_STACK() - * PJ_CHECK_STACK() macro is used to check the sanity of the stack. - * The OS implementation may check that no stack overflow occurs, and - * it also may collect statistic about stack usage. - */ -#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 - -# define PJ_CHECK_STACK() pj_thread_check_stack(__FILE__, __LINE__) - -/** @internal - * The implementation of stack checking. - */ -PJ_DECL(void) pj_thread_check_stack(const char *file, int line); - -/** @internal - * Get maximum stack usage statistic. - */ -PJ_DECL(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread); - -/** @internal - * Dump thread stack status. - */ -PJ_DECL(pj_status_t) pj_thread_get_stack_info(pj_thread_t *thread, - const char **file, - int *line); -#else - -# define PJ_CHECK_STACK() -/** pj_thread_get_stack_max_usage() for the thread */ -# define pj_thread_get_stack_max_usage(thread) 0 -/** pj_thread_get_stack_info() for the thread */ -# define pj_thread_get_stack_info(thread,f,l) (*(f)="",*(l)=0) -#endif /* PJ_OS_HAS_CHECK_STACK */ - -/** - * @} - */ - -/////////////////////////////////////////////////////////////////////////////// -/** - * @defgroup PJ_TLS Thread Local Storage. - * @ingroup PJ_OS - * @{ - */ - -/** - * Allocate thread local storage index. The initial value of the variable at - * the index is zero. - * - * @param index Pointer to hold the return value. - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_thread_local_alloc(long *index); - -/** - * Deallocate thread local variable. - * - * @param index The variable index. - */ -PJ_DECL(void) pj_thread_local_free(long index); - -/** - * Set the value of thread local variable. - * - * @param index The index of the variable. - * @param value The value. - */ -PJ_DECL(void) pj_thread_local_set(long index, void *value); - -/** - * Get the value of thread local variable. - * - * @param index The index of the variable. - * @return The value. - */ -PJ_DECL(void*) pj_thread_local_get(long index); - - -/** - * @} - */ - - -/////////////////////////////////////////////////////////////////////////////// -/** - * @defgroup PJ_ATOMIC Atomic Variables - * @ingroup PJ_OS - * @{ - * - * This module provides API to manipulate atomic variables. - * - * \section pj_atomic_examples_sec Examples - * - * For some example codes, please see: - * - @ref page_pjlib_atomic_test - */ - - -/** - * Create atomic variable. - * - * @param pool The pool. - * @param initial The initial value of the atomic variable. - * @param atomic Pointer to hold the atomic variable upon return. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_atomic_create( pj_pool_t *pool, - pj_atomic_value_t initial, - pj_atomic_t **atomic ); - -/** - * Destroy atomic variable. - * - * @param atomic_var the atomic variable. - * - * @return PJ_SUCCESS if success. - */ -PJ_DECL(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var ); - -/** - * Set the value of an atomic type, and return the previous value. - * - * @param atomic_var the atomic variable. - * @param value value to be set to the variable. - * - * @return the previous value of the variable. - */ -PJ_DECL(pj_atomic_value_t) pj_atomic_set(pj_atomic_t *atomic_var, - pj_atomic_value_t value); - -/** - * Get the value of an atomic type. - * - * @param atomic_var the atomic variable. - * - * @return the value of the atomic variable. - */ -PJ_DECL(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var); - -/** - * Increment the value of an atomic type. - * - * @param atomic_var the atomic variable. - * - * @return the result. - */ -PJ_DECL(pj_atomic_value_t) pj_atomic_inc(pj_atomic_t *atomic_var); - -/** - * Decrement the value of an atomic type. - * - * @param atomic_var the atomic variable. - * - * @return the result. - */ -PJ_DECL(pj_atomic_value_t) pj_atomic_dec(pj_atomic_t *atomic_var); - -/** - * @} - */ - -/////////////////////////////////////////////////////////////////////////////// -/** - * @defgroup PJ_MUTEX Mutexes. - * @ingroup PJ_OS - * @{ - * - * Mutex manipulation. Alternatively, application can use higher abstraction - * for lock objects, which provides uniform API for all kinds of lock - * mechanisms, including mutex. See @ref PJ_LOCK for more information. - */ - -/** - * Mutex types: - * - PJ_MUTEX_DEFAULT: default mutex type, which is system dependent. - * - PJ_MUTEX_SIMPLE: non-recursive mutex. - * - PJ_MUTEX_RECURSIVE: recursive mutex. - */ -typedef enum pj_mutex_type_e -{ - PJ_MUTEX_DEFAULT, - PJ_MUTEX_SIMPLE, - PJ_MUTEX_RECURSE, -} pj_mutex_type_e; - - -/** - * Create mutex of the specified type. - * - * @param pool The pool. - * @param name Name to be associated with the mutex (for debugging). - * @param type The type of the mutex, of type #pj_mutex_type_e. - * @param mutex Pointer to hold the returned mutex instance. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_mutex_create(pj_pool_t *pool, - const char *name, - int type, - pj_mutex_t **mutex); - -/** - * Create simple, non-recursive mutex. - * This function is a simple wrapper for #pj_mutex_create to create - * non-recursive mutex. - * - * @param pool The pool. - * @param name Mutex name. - * @param mutex Pointer to hold the returned mutex instance. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name, - pj_mutex_t **mutex ); - -/** - * Create recursive mutex. - * This function is a simple wrapper for #pj_mutex_create to create - * recursive mutex. - * - * @param pool The pool. - * @param name Mutex name. - * @param mutex Pointer to hold the returned mutex instance. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool, - const char *name, - pj_mutex_t **mutex ); - -/** - * Acquire mutex lock. - * - * @param mutex The mutex. - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex); - -/** - * Release mutex lock. - * - * @param mutex The mutex. - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex); - -/** - * Try to acquire mutex lock. - * - * @param mutex The mutex. - * @return PJ_SUCCESS on success, or the error code if the - * lock couldn't be acquired. - */ -PJ_DECL(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex); - -/** - * Destroy mutex. - * - * @param mutex Te mutex. - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex); - -/** - * Determine whether calling thread is owning the mutex (only available when - * PJ_DEBUG is set). - * @param mutex The mutex. - * @return Non-zero if yes. - */ -#if defined(PJ_DEBUG) && PJ_DEBUG != 0 - PJ_DECL(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex); -#else -# define pj_mutex_is_locked(mutex) 1 -#endif - -/** - * @} - */ - -/////////////////////////////////////////////////////////////////////////////// -/** - * @defgroup PJ_CRIT_SEC Critical sections. - * @ingroup PJ_OS - * @{ - * Critical section protection can be used to protect regions where: - * - mutual exclusion protection is needed. - * - it's rather too expensive to create a mutex. - * - the time spent in the region is very very brief. - * - * Critical section is a global object, and it prevents any threads from - * entering any regions that are protected by critical section once a thread - * is already in the section. - * - * Critial section is \a not recursive! - * - * Application MUST NOT call any functions that may cause current - * thread to block (such as allocating memory, performing I/O, locking mutex, - * etc.) while holding the critical section. - */ -/** - * Enter critical section. - */ -PJ_DECL(void) pj_enter_critical_section(void); - -/** - * Leave critical section. - */ -PJ_DECL(void) pj_leave_critical_section(void); - -/** - * @} - */ - -/////////////////////////////////////////////////////////////////////////////// -#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 -/** - * @defgroup PJ_SEM Semaphores. - * @ingroup PJ_OS - * @{ - * - * This module provides abstraction for semaphores, where available. - */ - -/** - * Create semaphore. - * - * @param pool The pool. - * @param name Name to be assigned to the semaphore (for logging purpose) - * @param initial The initial count of the semaphore. - * @param max The maximum count of the semaphore. - * @param sem Pointer to hold the semaphore created. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_sem_create( pj_pool_t *pool, - const char *name, - unsigned initial, - unsigned max, - pj_sem_t **sem); - -/** - * Wait for semaphore. - * - * @param sem The semaphore. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_sem_wait(pj_sem_t *sem); - -/** - * Try wait for semaphore. - * - * @param sem The semaphore. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_sem_trywait(pj_sem_t *sem); - -/** - * Release semaphore. - * - * @param sem The semaphore. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_sem_post(pj_sem_t *sem); - -/** - * Destroy semaphore. - * - * @param sem The semaphore. - * - * @return PJ_SUCCESS on success, or the error code. - */ -PJ_DECL(pj_status_t) pj_sem_destroy(pj_sem_t *sem); - -/** - * @} - */ -#endif /* PJ_HAS_SEMAPHORE */ - - -/////////////////////////////////////////////////////////////////////////////// -#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0 -/** - * @defgroup PJ_EVENT Event Object. - * @ingroup PJ_OS - * @{ - * - * This module provides abstraction to event object (e.g. Win32 Event) where - * available. Event objects can be used for synchronization among threads. - */ - -/** - * Create event object. - * - * @param pool The pool. - * @param name The name of the event object (for logging purpose). - * @param manual_reset Specify whether the event is manual-reset - * @param initial Specify the initial state of the event object. - * @param event Pointer to hold the returned event object. - * - * @return event handle, or NULL if failed. - */ -PJ_DECL(pj_status_t) pj_event_create(pj_pool_t *pool, const char *name, - pj_bool_t manual_reset, pj_bool_t initial, - pj_event_t **event); - -/** - * Wait for event to be signaled. - * - * @param event The event object. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_event_wait(pj_event_t *event); - -/** - * Try wait for event object to be signalled. - * - * @param event The event object. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_event_trywait(pj_event_t *event); - -/** - * Set the event object state to signaled. For auto-reset event, this - * will only release the first thread that are waiting on the event. For - * manual reset event, the state remains signaled until the event is reset. - * If there is no thread waiting on the event, the event object state - * remains signaled. - * - * @param event The event object. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_event_set(pj_event_t *event); - -/** - * Set the event object to signaled state to release appropriate number of - * waiting threads and then reset the event object to non-signaled. For - * manual-reset event, this function will release all waiting threads. For - * auto-reset event, this function will only release one waiting thread. - * - * @param event The event object. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_event_pulse(pj_event_t *event); - -/** - * Set the event object state to non-signaled. - * - * @param event The event object. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_event_reset(pj_event_t *event); - -/** - * Destroy the event object. - * - * @param event The event object. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_event_destroy(pj_event_t *event); - -/** - * @} - */ -#endif /* PJ_HAS_EVENT_OBJ */ - -/////////////////////////////////////////////////////////////////////////////// -/** - * @addtogroup PJ_TIME Time Data Type and Manipulation. - * @ingroup PJ_OS - * @{ - * This module provides API for manipulating time. - * - * \section pj_time_examples_sec Examples - * - * For examples, please see: - * - \ref page_pjlib_sleep_test - */ - -/** - * Get current time of day in local representation. - * - * @param tv Variable to store the result. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_gettimeofday(pj_time_val *tv); - - -/** - * Parse time value into date/time representation. - * - * @param tv The time. - * @param pt Variable to store the date time result. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt); - -/** - * Encode date/time to time value. - * - * @param pt The date/time. - * @param tv Variable to store time value result. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv); - -/** - * Convert local time to GMT. - * - * @param tv Time to convert. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv); - -/** - * Convert GMT to local time. - * - * @param tv Time to convert. - * - * @return zero if successfull. - */ -PJ_DECL(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv); - -/** - * @} - */ - -/////////////////////////////////////////////////////////////////////////////// -#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0 - -/** - * @defgroup PJ_TERM Terminal - * @ingroup PJ_OS - * @{ - */ - -/** - * Set current terminal color. - * - * @param color The RGB color. - * - * @return zero on success. - */ -PJ_DECL(pj_status_t) pj_term_set_color(pj_color_t color); - -/** - * Get current terminal foreground color. - * - * @return RGB color. - */ -PJ_DECL(pj_color_t) pj_term_get_color(void); - -/** - * @} - */ - -#endif /* PJ_TERM_HAS_COLOR */ - -/////////////////////////////////////////////////////////////////////////////// -/** - * @defgroup PJ_TIMESTAMP High Resolution Timestamp - * @ingroup PJ_OS - * @{ - * - * PJLIB provides High Resolution Timestamp API to access highest - * resolution timestamp value provided by the platform. The API is usefull - * to measure precise elapsed time, and can be used in applications such - * as profiling. - * - * The timestamp value is represented in cycles, and can be related to - * normal time (in seconds or sub-seconds) using various functions provided. - * - * \section pj_timestamp_examples_sec Examples - * - * For examples, please see: - * - \ref page_pjlib_sleep_test - * - \ref page_pjlib_timestamp_test - */ - -/* - * High resolution timer. - */ -#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0 - -/** - * This structure represents high resolution (64bit) time value. The time - * values represent time in cycles, which is retrieved by calling - * #pj_get_timestamp(). - */ -typedef union pj_timestamp -{ - struct - { - pj_uint32_t lo; /**< Low 32-bit value of the 64-bit value. */ - pj_uint32_t hi; /**< high 32-bit value of the 64-bit value. */ - } u32; /**< The 64-bit value as two 32-bit values. */ - -#if PJ_HAS_INT64 - pj_uint64_t u64; /**< The whole 64-bit value, where available. */ -#endif -} pj_timestamp; - - -/** - * Acquire high resolution timer value. The time value are stored - * in cycles. - * - * @param ts High resolution timer value. - * @return PJ_SUCCESS or the appropriate error code. - * - * @see pj_get_timestamp_freq(). - */ -PJ_DECL(pj_status_t) pj_get_timestamp(pj_timestamp *ts); - -/** - * Get high resolution timer frequency, in cycles per second. - * - * @param freq Timer frequency, in cycles per second. - * @return PJ_SUCCESS or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq); - -/** - * Calculate the elapsed time, and store it in pj_time_val. - * This function calculates the elapsed time using highest precision - * calculation that is available for current platform, considering - * whether floating point or 64-bit precision arithmetic is available. - * For maximum portability, application should prefer to use this function - * rather than calculating the elapsed time by itself. - * - * @param start The starting timestamp. - * @param stop The end timestamp. - * - * @return Elapsed time as #pj_time_val. - * - * @see pj_elapsed_usec(), pj_elapsed_cycle(), pj_elapsed_nanosec() - */ -PJ_DECL(pj_time_val) pj_elapsed_time( const pj_timestamp *start, - const pj_timestamp *stop ); - -/** - * Calculate the elapsed time in 32-bit microseconds. - * This function calculates the elapsed time using highest precision - * calculation that is available for current platform, considering - * whether floating point or 64-bit precision arithmetic is available. - * For maximum portability, application should prefer to use this function - * rather than calculating the elapsed time by itself. - * - * @param start The starting timestamp. - * @param stop The end timestamp. - * - * @return Elapsed time in microsecond. - * - * @see pj_elapsed_time(), pj_elapsed_cycle(), pj_elapsed_nanosec() - */ -PJ_DECL(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start, - const pj_timestamp *stop ); - -/** - * Calculate the elapsed time in 32-bit nanoseconds. - * This function calculates the elapsed time using highest precision - * calculation that is available for current platform, considering - * whether floating point or 64-bit precision arithmetic is available. - * For maximum portability, application should prefer to use this function - * rather than calculating the elapsed time by itself. - * - * @param start The starting timestamp. - * @param stop The end timestamp. - * - * @return Elapsed time in nanoseconds. - * - * @see pj_elapsed_time(), pj_elapsed_cycle(), pj_elapsed_usec() - */ -PJ_DECL(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start, - const pj_timestamp *stop ); - -/** - * Calculate the elapsed time in 32-bit cycles. - * This function calculates the elapsed time using highest precision - * calculation that is available for current platform, considering - * whether floating point or 64-bit precision arithmetic is available. - * For maximum portability, application should prefer to use this function - * rather than calculating the elapsed time by itself. - * - * @param start The starting timestamp. - * @param stop The end timestamp. - * - * @return Elapsed time in cycles. - * - * @see pj_elapsed_usec(), pj_elapsed_time(), pj_elapsed_nanosec() - */ -PJ_DECL(pj_uint32_t) pj_elapsed_cycle( const pj_timestamp *start, - const pj_timestamp *stop ); - - -#endif /* PJ_HAS_HIGH_RES_TIMER */ - -/** @} */ - - -/////////////////////////////////////////////////////////////////////////////// -/** - * Internal PJLIB function to initialize the threading subsystem. - * @return PJ_SUCCESS or the appropriate error code. - */ -pj_status_t pj_thread_init(void); - - -PJ_END_DECL - -#endif /* __PJ_OS_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/os.h 12 10/29/05 11:30a Bennylp $ */ + +#ifndef __PJ_OS_H__ +#define __PJ_OS_H__ + +/** + * @file os.h + * @brief OS dependent functions + */ +#include + +PJ_BEGIN_DECL + +/** + * @defgroup PJ_OS Operating System Dependent Functionality. + * @ingroup PJ + */ + + +/////////////////////////////////////////////////////////////////////////////// +/** + * @defgroup PJ_THREAD Threads + * @ingroup PJ_OS + * @{ + * This module provides multithreading API. + * + * \section pj_thread_examples_sec Examples + * + * For examples, please see: + * - \ref page_pjlib_thread_test + * - \ref page_pjlib_sleep_test + * + */ + +/** + * Thread creation flags: + * - PJ_THREAD_SUSPENDED: specify that the thread should be created suspended. + */ +typedef enum pj_thread_create_flags +{ + PJ_THREAD_SUSPENDED = 1 +} pj_thread_create_flags; + + +/** + * Specify this as \a stack_size argument in #pj_thread_create() to specify + * that thread should use default stack size for the current platform. + */ +#define PJ_THREAD_DEFAULT_STACK_SIZE 0 + +/** + * Type of thread entry function. + */ +typedef int (PJ_THREAD_FUNC pj_thread_proc)(void*); + +/** + * Size of thread struct. + */ +#if !defined(PJ_THREAD_DESC_SIZE) +# define PJ_THREAD_DESC_SIZE (16) +#endif + +/** + * Thread structure, to thread's state when the thread is created by external + * or native API. + */ +typedef long pj_thread_desc[PJ_THREAD_DESC_SIZE]; + +/** + * Get process ID. + * @return process ID. + */ +PJ_DECL(pj_uint32_t) pj_getpid(void); + +/** + * Create a new thread. + * + * @param pool The memory pool from which the thread record + * will be allocated from. + * @param thread_name The optional name to be assigned to the thread. + * @param proc Thread entry function. + * @param arg Argument to be passed to the thread entry function. + * @param stack_size The size of the stack for the new thread, or ZERO or + * PJ_THREAD_DEFAULT_STACK_SIZE to let the + * library choose the reasonable size for the stack. + * For some systems, the stack will be allocated from + * the pool, so the pool must have suitable capacity. + * @param flags Flags for thread creation, which is bitmask combination + * from enum pj_thread_create_flags. + * @param thread Pointer to hold the newly created thread. + * + * @return PJ_SUCCESS on success, or the error code. + */ +PJ_DECL(pj_status_t) pj_thread_create( pj_pool_t *pool, + const char *thread_name, + pj_thread_proc *proc, + void *arg, + pj_size_t stack_size, + unsigned flags, + pj_thread_t **thread ); + +/** + * Register a thread that was created by external or native API to PJLIB. + * This function must be called in the context of the thread being registered. + * When the thread is created by external function or API call, + * it must be 'registered' to PJLIB using pj_thread_register(), so that it can + * cooperate with PJLIB's framework. During registration, some data needs to + * be maintained, and this data must remain available during the thread's + * lifetime. + * + * @param thread_name The optional name to be assigned to the thread. + * @param desc Thread descriptor, which must be available throughout + * the lifetime of the thread. + * @param thread Pointer to hold the created thread handle. + * + * @return PJ_SUCCESS on success, or the error code. + */ +PJ_DECL(pj_status_t) pj_thread_register ( const char *thread_name, + pj_thread_desc desc, + pj_thread_t **thread); + +/** + * Get thread name. + * + * @param thread The thread handle. + * + * @return Thread name as null terminated string. + */ +PJ_DECL(const char*) pj_thread_get_name(pj_thread_t *thread); + +/** + * Resume a suspended thread. + * + * @param thread The thread handle. + * + * @return zero on success. + */ +PJ_DECL(pj_status_t) pj_thread_resume(pj_thread_t *thread); + +/** + * Get the current thread. + * + * @return Thread handle of current thread. + */ +PJ_DECL(pj_thread_t*) pj_thread_this(void); + +/** + * Join thread. + * This function will block the caller thread until the specified thread exits. + * + * @param thread The thread handle. + * + * @return zero on success. + */ +PJ_DECL(pj_status_t) pj_thread_join(pj_thread_t *thread); + + +/** + * Destroy thread and release resources allocated for the thread. + * However, the memory allocated for the pj_thread_t itself will only be released + * when the pool used to create the thread is destroyed. + * + * @param thread The thread handle. + * + * @return zero on success. + */ +PJ_DECL(pj_status_t) pj_thread_destroy(pj_thread_t *thread); + + +/** + * Put the current thread to sleep for the specified miliseconds. + * + * @param msec Miliseconds delay. + * + * @return zero if successfull. + */ +PJ_DECL(pj_status_t) pj_thread_sleep(unsigned msec); + +/** + * @def PJ_CHECK_STACK() + * PJ_CHECK_STACK() macro is used to check the sanity of the stack. + * The OS implementation may check that no stack overflow occurs, and + * it also may collect statistic about stack usage. + */ +#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 + +# define PJ_CHECK_STACK() pj_thread_check_stack(__FILE__, __LINE__) + +/** @internal + * The implementation of stack checking. + */ +PJ_DECL(void) pj_thread_check_stack(const char *file, int line); + +/** @internal + * Get maximum stack usage statistic. + */ +PJ_DECL(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread); + +/** @internal + * Dump thread stack status. + */ +PJ_DECL(pj_status_t) pj_thread_get_stack_info(pj_thread_t *thread, + const char **file, + int *line); +#else + +# define PJ_CHECK_STACK() +/** pj_thread_get_stack_max_usage() for the thread */ +# define pj_thread_get_stack_max_usage(thread) 0 +/** pj_thread_get_stack_info() for the thread */ +# define pj_thread_get_stack_info(thread,f,l) (*(f)="",*(l)=0) +#endif /* PJ_OS_HAS_CHECK_STACK */ + +/** + * @} + */ + +/////////////////////////////////////////////////////////////////////////////// +/** + * @defgroup PJ_TLS Thread Local Storage. + * @ingroup PJ_OS + * @{ + */ + +/** + * Allocate thread local storage index. The initial value of the variable at + * the index is zero. + * + * @param index Pointer to hold the return value. + * @return PJ_SUCCESS on success, or the error code. + */ +PJ_DECL(pj_status_t) pj_thread_local_alloc(long *index); + +/** + * Deallocate thread local variable. + * + * @param index The variable index. + */ +PJ_DECL(void) pj_thread_local_free(long index); + +/** + * Set the value of thread local variable. + * + * @param index The index of the variable. + * @param value The value. + */ +PJ_DECL(pj_status_t) pj_thread_local_set(long index, void *value); + +/** + * Get the value of thread local variable. + * + * @param index The index of the variable. + * @return The value. + */ +PJ_DECL(void*) pj_thread_local_get(long index); + + +/** + * @} + */ + + +/////////////////////////////////////////////////////////////////////////////// +/** + * @defgroup PJ_ATOMIC Atomic Variables + * @ingroup PJ_OS + * @{ + * + * This module provides API to manipulate atomic variables. + * + * \section pj_atomic_examples_sec Examples + * + * For some example codes, please see: + * - @ref page_pjlib_atomic_test + */ + + +/** + * Create atomic variable. + * + * @param pool The pool. + * @param initial The initial value of the atomic variable. + * @param atomic Pointer to hold the atomic variable upon return. + * + * @return PJ_SUCCESS on success, or the error code. + */ +PJ_DECL(pj_status_t) pj_atomic_create( pj_pool_t *pool, + pj_atomic_value_t initial, + pj_atomic_t **atomic ); + +/** + * Destroy atomic variable. + * + * @param atomic_var the atomic variable. + * + * @return PJ_SUCCESS if success. + */ +PJ_DECL(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var ); + +/** + * Set the value of an atomic type, and return the previous value. + * + * @param atomic_var the atomic variable. + * @param value value to be set to the variable. + * + * @return the previous value of the variable. + */ +PJ_DECL(pj_atomic_value_t) pj_atomic_set(pj_atomic_t *atomic_var, + pj_atomic_value_t value); + +/** + * Get the value of an atomic type. + * + * @param atomic_var the atomic variable. + * + * @return the value of the atomic variable. + */ +PJ_DECL(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var); + +/** + * Increment the value of an atomic type. + * + * @param atomic_var the atomic variable. + * + * @return the result. + */ +PJ_DECL(pj_atomic_value_t) pj_atomic_inc(pj_atomic_t *atomic_var); + +/** + * Decrement the value of an atomic type. + * + * @param atomic_var the atomic variable. + * + * @return the result. + */ +PJ_DECL(pj_atomic_value_t) pj_atomic_dec(pj_atomic_t *atomic_var); + +/** + * @} + */ + +/////////////////////////////////////////////////////////////////////////////// +/** + * @defgroup PJ_MUTEX Mutexes. + * @ingroup PJ_OS + * @{ + * + * Mutex manipulation. Alternatively, application can use higher abstraction + * for lock objects, which provides uniform API for all kinds of lock + * mechanisms, including mutex. See @ref PJ_LOCK for more information. + */ + +/** + * Mutex types: + * - PJ_MUTEX_DEFAULT: default mutex type, which is system dependent. + * - PJ_MUTEX_SIMPLE: non-recursive mutex. + * - PJ_MUTEX_RECURSIVE: recursive mutex. + */ +typedef enum pj_mutex_type_e +{ + PJ_MUTEX_DEFAULT, + PJ_MUTEX_SIMPLE, + PJ_MUTEX_RECURSE, +} pj_mutex_type_e; + + +/** + * Create mutex of the specified type. + * + * @param pool The pool. + * @param name Name to be associated with the mutex (for debugging). + * @param type The type of the mutex, of type #pj_mutex_type_e. + * @param mutex Pointer to hold the returned mutex instance. + * + * @return PJ_SUCCESS on success, or the error code. + */ +PJ_DECL(pj_status_t) pj_mutex_create(pj_pool_t *pool, + const char *name, + int type, + pj_mutex_t **mutex); + +/** + * Create simple, non-recursive mutex. + * This function is a simple wrapper for #pj_mutex_create to create + * non-recursive mutex. + * + * @param pool The pool. + * @param name Mutex name. + * @param mutex Pointer to hold the returned mutex instance. + * + * @return PJ_SUCCESS on success, or the error code. + */ +PJ_DECL(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name, + pj_mutex_t **mutex ); + +/** + * Create recursive mutex. + * This function is a simple wrapper for #pj_mutex_create to create + * recursive mutex. + * + * @param pool The pool. + * @param name Mutex name. + * @param mutex Pointer to hold the returned mutex instance. + * + * @return PJ_SUCCESS on success, or the error code. + */ +PJ_DECL(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool, + const char *name, + pj_mutex_t **mutex ); + +/** + * Acquire mutex lock. + * + * @param mutex The mutex. + * @return PJ_SUCCESS on success, or the error code. + */ +PJ_DECL(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex); + +/** + * Release mutex lock. + * + * @param mutex The mutex. + * @return PJ_SUCCESS on success, or the error code. + */ +PJ_DECL(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex); + +/** + * Try to acquire mutex lock. + * + * @param mutex The mutex. + * @return PJ_SUCCESS on success, or the error code if the + * lock couldn't be acquired. + */ +PJ_DECL(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex); + +/** + * Destroy mutex. + * + * @param mutex Te mutex. + * @return PJ_SUCCESS on success, or the error code. + */ +PJ_DECL(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex); + +/** + * Determine whether calling thread is owning the mutex (only available when + * PJ_DEBUG is set). + * @param mutex The mutex. + * @return Non-zero if yes. + */ +#if defined(PJ_DEBUG) && PJ_DEBUG != 0 + PJ_DECL(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex); +#else +# define pj_mutex_is_locked(mutex) 1 +#endif + +/** + * @} + */ + +/////////////////////////////////////////////////////////////////////////////// +/** + * @defgroup PJ_CRIT_SEC Critical sections. + * @ingroup PJ_OS + * @{ + * Critical section protection can be used to protect regions where: + * - mutual exclusion protection is needed. + * - it's rather too expensive to create a mutex. + * - the time spent in the region is very very brief. + * + * Critical section is a global object, and it prevents any threads from + * entering any regions that are protected by critical section once a thread + * is already in the section. + * + * Critial section is \a not recursive! + * + * Application MUST NOT call any functions that may cause current + * thread to block (such as allocating memory, performing I/O, locking mutex, + * etc.) while holding the critical section. + */ +/** + * Enter critical section. + */ +PJ_DECL(void) pj_enter_critical_section(void); + +/** + * Leave critical section. + */ +PJ_DECL(void) pj_leave_critical_section(void); + +/** + * @} + */ + +/////////////////////////////////////////////////////////////////////////////// +#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 +/** + * @defgroup PJ_SEM Semaphores. + * @ingroup PJ_OS + * @{ + * + * This module provides abstraction for semaphores, where available. + */ + +/** + * Create semaphore. + * + * @param pool The pool. + * @param name Name to be assigned to the semaphore (for logging purpose) + * @param initial The initial count of the semaphore. + * @param max The maximum count of the semaphore. + * @param sem Pointer to hold the semaphore created. + * + * @return PJ_SUCCESS on success, or the error code. + */ +PJ_DECL(pj_status_t) pj_sem_create( pj_pool_t *pool, + const char *name, + unsigned initial, + unsigned max, + pj_sem_t **sem); + +/** + * Wait for semaphore. + * + * @param sem The semaphore. + * + * @return PJ_SUCCESS on success, or the error code. + */ +PJ_DECL(pj_status_t) pj_sem_wait(pj_sem_t *sem); + +/** + * Try wait for semaphore. + * + * @param sem The semaphore. + * + * @return PJ_SUCCESS on success, or the error code. + */ +PJ_DECL(pj_status_t) pj_sem_trywait(pj_sem_t *sem); + +/** + * Release semaphore. + * + * @param sem The semaphore. + * + * @return PJ_SUCCESS on success, or the error code. + */ +PJ_DECL(pj_status_t) pj_sem_post(pj_sem_t *sem); + +/** + * Destroy semaphore. + * + * @param sem The semaphore. + * + * @return PJ_SUCCESS on success, or the error code. + */ +PJ_DECL(pj_status_t) pj_sem_destroy(pj_sem_t *sem); + +/** + * @} + */ +#endif /* PJ_HAS_SEMAPHORE */ + + +/////////////////////////////////////////////////////////////////////////////// +#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0 +/** + * @defgroup PJ_EVENT Event Object. + * @ingroup PJ_OS + * @{ + * + * This module provides abstraction to event object (e.g. Win32 Event) where + * available. Event objects can be used for synchronization among threads. + */ + +/** + * Create event object. + * + * @param pool The pool. + * @param name The name of the event object (for logging purpose). + * @param manual_reset Specify whether the event is manual-reset + * @param initial Specify the initial state of the event object. + * @param event Pointer to hold the returned event object. + * + * @return event handle, or NULL if failed. + */ +PJ_DECL(pj_status_t) pj_event_create(pj_pool_t *pool, const char *name, + pj_bool_t manual_reset, pj_bool_t initial, + pj_event_t **event); + +/** + * Wait for event to be signaled. + * + * @param event The event object. + * + * @return zero if successfull. + */ +PJ_DECL(pj_status_t) pj_event_wait(pj_event_t *event); + +/** + * Try wait for event object to be signalled. + * + * @param event The event object. + * + * @return zero if successfull. + */ +PJ_DECL(pj_status_t) pj_event_trywait(pj_event_t *event); + +/** + * Set the event object state to signaled. For auto-reset event, this + * will only release the first thread that are waiting on the event. For + * manual reset event, the state remains signaled until the event is reset. + * If there is no thread waiting on the event, the event object state + * remains signaled. + * + * @param event The event object. + * + * @return zero if successfull. + */ +PJ_DECL(pj_status_t) pj_event_set(pj_event_t *event); + +/** + * Set the event object to signaled state to release appropriate number of + * waiting threads and then reset the event object to non-signaled. For + * manual-reset event, this function will release all waiting threads. For + * auto-reset event, this function will only release one waiting thread. + * + * @param event The event object. + * + * @return zero if successfull. + */ +PJ_DECL(pj_status_t) pj_event_pulse(pj_event_t *event); + +/** + * Set the event object state to non-signaled. + * + * @param event The event object. + * + * @return zero if successfull. + */ +PJ_DECL(pj_status_t) pj_event_reset(pj_event_t *event); + +/** + * Destroy the event object. + * + * @param event The event object. + * + * @return zero if successfull. + */ +PJ_DECL(pj_status_t) pj_event_destroy(pj_event_t *event); + +/** + * @} + */ +#endif /* PJ_HAS_EVENT_OBJ */ + +/////////////////////////////////////////////////////////////////////////////// +/** + * @addtogroup PJ_TIME Time Data Type and Manipulation. + * @ingroup PJ_OS + * @{ + * This module provides API for manipulating time. + * + * \section pj_time_examples_sec Examples + * + * For examples, please see: + * - \ref page_pjlib_sleep_test + */ + +/** + * Get current time of day in local representation. + * + * @param tv Variable to store the result. + * + * @return zero if successfull. + */ +PJ_DECL(pj_status_t) pj_gettimeofday(pj_time_val *tv); + + +/** + * Parse time value into date/time representation. + * + * @param tv The time. + * @param pt Variable to store the date time result. + * + * @return zero if successfull. + */ +PJ_DECL(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt); + +/** + * Encode date/time to time value. + * + * @param pt The date/time. + * @param tv Variable to store time value result. + * + * @return zero if successfull. + */ +PJ_DECL(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv); + +/** + * Convert local time to GMT. + * + * @param tv Time to convert. + * + * @return zero if successfull. + */ +PJ_DECL(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv); + +/** + * Convert GMT to local time. + * + * @param tv Time to convert. + * + * @return zero if successfull. + */ +PJ_DECL(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv); + +/** + * @} + */ + +/////////////////////////////////////////////////////////////////////////////// +#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0 + +/** + * @defgroup PJ_TERM Terminal + * @ingroup PJ_OS + * @{ + */ + +/** + * Set current terminal color. + * + * @param color The RGB color. + * + * @return zero on success. + */ +PJ_DECL(pj_status_t) pj_term_set_color(pj_color_t color); + +/** + * Get current terminal foreground color. + * + * @return RGB color. + */ +PJ_DECL(pj_color_t) pj_term_get_color(void); + +/** + * @} + */ + +#endif /* PJ_TERM_HAS_COLOR */ + +/////////////////////////////////////////////////////////////////////////////// +/** + * @defgroup PJ_TIMESTAMP High Resolution Timestamp + * @ingroup PJ_OS + * @{ + * + * PJLIB provides High Resolution Timestamp API to access highest + * resolution timestamp value provided by the platform. The API is usefull + * to measure precise elapsed time, and can be used in applications such + * as profiling. + * + * The timestamp value is represented in cycles, and can be related to + * normal time (in seconds or sub-seconds) using various functions provided. + * + * \section pj_timestamp_examples_sec Examples + * + * For examples, please see: + * - \ref page_pjlib_sleep_test + * - \ref page_pjlib_timestamp_test + */ + +/* + * High resolution timer. + */ +#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0 + +/** + * This structure represents high resolution (64bit) time value. The time + * values represent time in cycles, which is retrieved by calling + * #pj_get_timestamp(). + */ +typedef union pj_timestamp +{ + struct + { +#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0 + pj_uint32_t lo; /**< Low 32-bit value of the 64-bit value. */ + pj_uint32_t hi; /**< high 32-bit value of the 64-bit value. */ +#else + pj_uint32_t hi; /**< high 32-bit value of the 64-bit value. */ + pj_uint32_t lo; /**< Low 32-bit value of the 64-bit value. */ +#endif + } u32; /**< The 64-bit value as two 32-bit values. */ + +#if PJ_HAS_INT64 + pj_uint64_t u64; /**< The whole 64-bit value, where available. */ +#endif +} pj_timestamp; + + +/** + * Acquire high resolution timer value. The time value are stored + * in cycles. + * + * @param ts High resolution timer value. + * @return PJ_SUCCESS or the appropriate error code. + * + * @see pj_get_timestamp_freq(). + */ +PJ_DECL(pj_status_t) pj_get_timestamp(pj_timestamp *ts); + +/** + * Get high resolution timer frequency, in cycles per second. + * + * @param freq Timer frequency, in cycles per second. + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq); + +/** + * Calculate the elapsed time, and store it in pj_time_val. + * This function calculates the elapsed time using highest precision + * calculation that is available for current platform, considering + * whether floating point or 64-bit precision arithmetic is available. + * For maximum portability, application should prefer to use this function + * rather than calculating the elapsed time by itself. + * + * @param start The starting timestamp. + * @param stop The end timestamp. + * + * @return Elapsed time as #pj_time_val. + * + * @see pj_elapsed_usec(), pj_elapsed_cycle(), pj_elapsed_nanosec() + */ +PJ_DECL(pj_time_val) pj_elapsed_time( const pj_timestamp *start, + const pj_timestamp *stop ); + +/** + * Calculate the elapsed time in 32-bit microseconds. + * This function calculates the elapsed time using highest precision + * calculation that is available for current platform, considering + * whether floating point or 64-bit precision arithmetic is available. + * For maximum portability, application should prefer to use this function + * rather than calculating the elapsed time by itself. + * + * @param start The starting timestamp. + * @param stop The end timestamp. + * + * @return Elapsed time in microsecond. + * + * @see pj_elapsed_time(), pj_elapsed_cycle(), pj_elapsed_nanosec() + */ +PJ_DECL(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start, + const pj_timestamp *stop ); + +/** + * Calculate the elapsed time in 32-bit nanoseconds. + * This function calculates the elapsed time using highest precision + * calculation that is available for current platform, considering + * whether floating point or 64-bit precision arithmetic is available. + * For maximum portability, application should prefer to use this function + * rather than calculating the elapsed time by itself. + * + * @param start The starting timestamp. + * @param stop The end timestamp. + * + * @return Elapsed time in nanoseconds. + * + * @see pj_elapsed_time(), pj_elapsed_cycle(), pj_elapsed_usec() + */ +PJ_DECL(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start, + const pj_timestamp *stop ); + +/** + * Calculate the elapsed time in 32-bit cycles. + * This function calculates the elapsed time using highest precision + * calculation that is available for current platform, considering + * whether floating point or 64-bit precision arithmetic is available. + * For maximum portability, application should prefer to use this function + * rather than calculating the elapsed time by itself. + * + * @param start The starting timestamp. + * @param stop The end timestamp. + * + * @return Elapsed time in cycles. + * + * @see pj_elapsed_usec(), pj_elapsed_time(), pj_elapsed_nanosec() + */ +PJ_DECL(pj_uint32_t) pj_elapsed_cycle( const pj_timestamp *start, + const pj_timestamp *stop ); + + +#endif /* PJ_HAS_HIGH_RES_TIMER */ + +/** @} */ + + +/////////////////////////////////////////////////////////////////////////////// +/** + * Internal PJLIB function to initialize the threading subsystem. + * @return PJ_SUCCESS or the appropriate error code. + */ +pj_status_t pj_thread_init(void); + + +PJ_END_DECL + +#endif /* __PJ_OS_H__ */ + diff --git a/pjlib/include/pj/pool.h b/pjlib/include/pj/pool.h index 78ed45b4..270ae71e 100644 --- a/pjlib/include/pj/pool.h +++ b/pjlib/include/pj/pool.h @@ -1,570 +1,570 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/pool.h 10 10/14/05 12:26a Bennylp $ */ - -#ifndef __PJ_POOL_H__ -#define __PJ_POOL_H__ - -/** - * @file pool.h - * @brief Memory Pool. - */ - -#include - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_POOL_GROUP Memory Pool Management - * @ingroup PJ - * @brief - * Memory pool management provides API to allocate and deallocate memory from - * memory pool and to manage and establish policy for pool creation and - * destruction in pool factory. - * - * \section PJ_POOL_FACTORY_SEC Pool Factory - * See: \ref PJ_POOL_FACTORY "Pool Factory" - * - * A memory pool must be created through a factory. A factory not only provides - * generic interface functions to create and release pool, but also provides - * strategy to manage the life time of pools. One sample implementation, - * \a pj_caching_pool, can be set to keep the pools released by application for - * future use as long as the total memory is below the limit. - * - * The pool factory interface declared in PJLIB is designed to be extensible. - * Application can define its own strategy by creating it's own pool factory - * implementation, and this strategy can be used even by existing library - * without recompilation. - * - * - * \section PJ_POOL_POLICY_SEC Pool Factory Policy - * See: \ref PJ_POOL_FACTORY "Pool Factory Policy" - * - * A pool factory only defines functions to create and release pool and how - * to manage pools, but the rest of the functionalities are controlled by - * policy. A pool policy defines: - * - how memory block is allocated and deallocated (the default implementation - * allocates and deallocate memory by calling malloc() and free()). - * - callback to be called when memory allocation inside a pool fails (the - * default implementation will throw PJ_NO_MEMORY_EXCEPTION exception). - * - concurrency when creating and releasing pool from/to the factory. - * - * A pool factory can be given different policy during creation to make - * it behave differently. For example, caching pool factory can be configured - * to allocate and deallocate from a static/contiguous/preallocated memory - * instead of using malloc()/free(). - * - * What strategy/factory and what policy to use is not defined by PJLIB, but - * instead is left to application to make use whichever is most efficient for - * itself. - * - * - * \section PJ_POOL_POOL_SEC The Pool - * See: \ref PJ_POOL "Pool" - * - * The memory pool is an opaque object created by pool factory. - * Application uses this object to request a memory chunk, by calling - * #pj_pool_alloc or #pj_pool_calloc. When the application has finished using - * the pool, it must call #pj_pool_release to free all the chunks previously - * allocated and release the pool back to the factory. - * - * \section PJ_POOL_THREADING_SEC More on Threading Policies: - * - By design, memory allocation from a pool is not thread safe. We assumed - * that a pool will be owned by an object, and thread safety should be - * handled by that object. Thus these functions are not thread safe: - * - #pj_pool_alloc, - * - #pj_pool_calloc, - * - and other pool statistic functions. - * - Threading in the pool factory is decided by the policy set for the - * factory when it was created. - * - * \section PJ_POOL_EXAMPLES_SEC Examples - * - * For some sample codes on how to use the pool, please see: - * - @ref page_pjlib_pool_test - */ - -/** - * @defgroup PJ_POOL Memory Pool. - * @ingroup PJ_POOL_GROUP - * @brief - * A memory pool is initialized with an initial amount of memory, which is - * called a block. Pool can be configured to dynamically allocate more memory - * blocks when it runs out of memory. Subsequent memory allocations by user - * will use up portions of these block. - * The pool doesn't keep track of individual memory allocations - * by user, and the user doesn't have to free these indidual allocations. This - * makes memory allocation simple and very fast. All the memory allocated from - * the pool will be destroyed when the pool itself is destroyed. - * @{ - */ - -/** - * The type for function to receive callback from the pool when it is unable - * to allocate memory. The elegant way to handle this condition is to throw - * exception, and this is what is expected by most of this library - * components. - */ -typedef void pj_pool_callback(pj_pool_t *pool, pj_size_t size); - -/** - * This class, which is used internally by the pool, describes a single - * block of memory from which user memory allocations will be allocated from. - */ -typedef struct pj_pool_block -{ - PJ_DECL_LIST_MEMBER(struct pj_pool_block) /**< List's prev and next. */ - unsigned char *buf; /**< Start of buffer. */ - unsigned char *cur; /**< Current alloc ptr. */ - unsigned char *end; /**< End of buffer. */ -} pj_pool_block; - - -/** - * This structure describes the memory pool. Only implementors of pool factory - * need to care about the contents of this structure. - */ -struct pj_pool_t -{ - PJ_DECL_LIST_MEMBER(struct pj_pool_t) - - /** Pool name */ - char obj_name[PJ_MAX_OBJ_NAME]; - - /** Pool factory. */ - pj_pool_factory *factory; - - /** Current capacity allocated by the pool. */ - pj_size_t capacity; - - /** Number of memory used/allocated. */ - pj_size_t used_size; - - /** Size of memory block to be allocated when the pool runs out of memory */ - pj_size_t increment_size; - - /** List of memory blocks allcoated by the pool. */ - pj_pool_block block_list; - - /** The callback to be called when the pool is unable to allocate memory. */ - pj_pool_callback *callback; - -}; - - -/** - * Guidance on how much memory required for initial pool administrative data. - */ -#define PJ_POOL_SIZE (sizeof(struct pj_pool_t)) - -/** - * Pool memory alignment (must be power of 2). - */ -#ifndef PJ_POOL_ALIGNMENT -# define PJ_POOL_ALIGNMENT 4 -#endif - -/** - * Create a new pool from the pool factory. This wrapper will call create_pool - * member of the pool factory. - * - * @param factory The pool factory. - * @param name The name to be assigned to the pool. The name should - * not be longer than PJ_MAX_OBJ_NAME (32 chars), or - * otherwise it will be truncated. - * @param initial_size The size of initial memory blocks taken by the pool. - * Note that the pool will take 68+20 bytes for - * administrative area from this block. - * @param increment_size the size of each additional blocks to be allocated - * when the pool is running out of memory. If user - * requests memory which is larger than this size, then - * an error occurs. - * Note that each time a pool allocates additional block, - * it needs PJ_POOL_SIZE more to store some - * administrative info. - * @param callback Callback to be called when error occurs in the pool. - * If this value is NULL, then the callback from pool - * factory policy will be used. - * Note that when an error occurs during pool creation, - * the callback itself is not called. Instead, NULL - * will be returned. - * - * @return The memory pool, or NULL. - */ -PJ_IDECL(pj_pool_t*) pj_pool_create(pj_pool_factory *factory, - const char *name, - pj_size_t initial_size, - pj_size_t increment_size, - pj_pool_callback *callback); - -/** - * Release the pool back to pool factory. - * - * @param pool Memory pool. - */ -PJ_IDECL(void) pj_pool_release( pj_pool_t *pool ); - -/** - * Get pool object name. - * - * @param pool the pool. - * - * @return pool name as NULL terminated string. - */ -PJ_IDECL(const char *) pj_pool_getobjname( const pj_pool_t *pool ); - -/** - * Reset the pool to its state when it was initialized. - * This means that if additional blocks have been allocated during runtime, - * then they will be freed. Only the original block allocated during - * initialization is retained. This function will also reset the internal - * counters, such as pool capacity and used size. - * - * @param pool the pool. - */ -PJ_DECL(void) pj_pool_reset( pj_pool_t *pool ); - - -/** - * Get the pool capacity, that is, the system storage that have been allocated - * by the pool, and have been used/will be used to allocate user requests. - * There's no guarantee that the returned value represent a single - * contiguous block, because the capacity may be spread in several blocks. - * - * @param pool the pool. - * - * @return the capacity. - */ -PJ_IDECL(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool ); - -/** - * Get the total size of user allocation request. - * - * @param pool the pool. - * - * @return the total size. - */ -PJ_IDECL(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool ); - -/** - * Allocate storage with the specified size from the pool. - * If there's no storage available in the pool, then the pool can allocate more - * blocks if the increment size is larger than the requested size. - * - * @param pool the pool. - * @param size the requested size. - * - * @return pointer to the allocated memory. - */ -PJ_IDECL(void*) pj_pool_alloc( pj_pool_t *pool, pj_size_t size); - -/** - * Allocate storage from the pool, and initialize it to zero. - * This function behaves like pj_pool_alloc(), except that the storage will - * be initialized to zero. - * - * @param pool the pool. - * @param count the number of elements in the array. - * @param elem the size of individual element. - * - * @return pointer to the allocated memory. - */ -PJ_IDECL(void*) pj_pool_calloc( pj_pool_t *pool, pj_size_t count, - pj_size_t elem); - - -/** - * @def pj_pool_zalloc(pj_pool_t *pool, pj_size_t size) - * Allocate storage from the pool and initialize it to zero. - * - * @param pool The pool. - * @param size The size to be allocated. - * - * @return Pointer to the allocated memory. - */ -#define pj_pool_zalloc(pool, size) pj_pool_calloc(pool, 1, size) - - -/** - * @} // PJ_POOL - */ - -/////////////////////////////////////////////////////////////////////////////// -/** - * @defgroup PJ_POOL_FACTORY Pool Factory and Policy. - * @ingroup PJ_POOL_GROUP - * @brief - * Pool factory declares an interface to create and destroy pool. There may - * be several strategies for pool creation, and these strategies should - * implement the interface defined by pool factory. - * - * \section PJ_POOL_FACTORY_ITF Pool Factory Interface - * The pool factory defines the following interface: - * - \a policy: the memory pool factory policy. - * - \a create_pool(): create a new memory pool. - * - \a release_pool(): release memory pool back to factory. - * - * \section PJ_POOL_FACTORY_POL Pool Factory Policy. - * The pool factory policy controls the behaviour of memory factories, and - * defines the following interface: - * - \a block_alloc(): allocate memory block from backend memory mgmt/system. - * - \a block_free(): free memory block back to backend memory mgmt/system. - * @{ - */ - -/* We unfortunately don't have support for factory policy options as now, - so we keep this commented at the moment. -enum PJ_POOL_FACTORY_OPTION -{ - PJ_POOL_FACTORY_SERIALIZE = 1 -}; -*/ - -/** - * This structure declares pool factory interface. - */ -typedef struct pj_pool_factory_policy -{ - /** - * Allocate memory block (for use by pool). This function is called - * by memory pool to allocate memory block. - * - * @param factory Pool factory. - * @param size The size of memory block to allocate. - * - * @return Memory block. - */ - void* (*block_alloc)(pj_pool_factory *factory, pj_size_t size); - - /** - * Free memory block. - * - * @param factory Pool factory. - * @param mem Memory block previously allocated by block_alloc(). - * @param size The size of memory block. - */ - void (*block_free)(pj_pool_factory *factory, void *mem, pj_size_t size); - - /** - * Default callback to be called when memory allocation fails. - */ - pj_pool_callback *callback; - - /** - * Option flags. - */ - unsigned flags; - -} pj_pool_factory_policy; - -/** - * This constant denotes the exception number that will be thrown by default - * memory factory policy when memory allocation fails. - */ -extern int PJ_NO_MEMORY_EXCEPTION; - -/** - * This global variable points to default memory pool factory policy. - * The behaviour of the default policy is: - * - block allocation and deallocation use malloc() and free(). - * - callback will raise PJ_NO_MEMORY_EXCEPTION exception. - * - access to pool factory is not serialized (i.e. not thread safe). - */ -extern pj_pool_factory_policy pj_pool_factory_default_policy; - -/** - * This structure contains the declaration for pool factory interface. - */ -struct pj_pool_factory -{ - /** - * Memory pool policy. - */ - pj_pool_factory_policy policy; - - /** - * Create a new pool from the pool factory. - * - * @param factory The pool factory. - * @param name the name to be assigned to the pool. The name should - * not be longer than PJ_MAX_OBJ_NAME (32 chars), or - * otherwise it will be truncated. - * @param initial_size the size of initial memory blocks taken by the pool. - * Note that the pool will take 68+20 bytes for - * administrative area from this block. - * @param increment_size the size of each additional blocks to be allocated - * when the pool is running out of memory. If user - * requests memory which is larger than this size, then - * an error occurs. - * Note that each time a pool allocates additional block, - * it needs 20 bytes (equal to sizeof(pj_pool_block)) to - * store some administrative info. - * @param callback Cllback to be called when error occurs in the pool. - * Note that when an error occurs during pool creation, - * the callback itself is not called. Instead, NULL - * will be returned. - * - * @return the memory pool, or NULL. - */ - pj_pool_t* (*create_pool)( pj_pool_factory *factory, - const char *name, - pj_size_t initial_size, - pj_size_t increment_size, - pj_pool_callback *callback); - - /** - * Release the pool to the pool factory. - * - * @param factory The pool factory. - * @param pool The pool to be released. - */ - void (*release_pool)( pj_pool_factory *factory, pj_pool_t *pool ); - - /** - * Dump pool status to log. - * - * @param factory The pool factory. - */ - void (*dump_status)( pj_pool_factory *factory, pj_bool_t detail ); -}; - -/** - * This function is intended to be used by pool factory implementors. - * @param factory Pool factory. - * @param name Pool name. - * @param initial_size Initial size. - * @param increment_size Increment size. - * @param callback Callback. - * @return The pool object, or NULL. - */ -PJ_DECL(pj_pool_t*) pj_pool_create_int( pj_pool_factory *factory, - const char *name, - pj_size_t initial_size, - pj_size_t increment_size, - pj_pool_callback *callback); - -/** - * This function is intended to be used by pool factory implementors. - * @param pool The pool. - * @param name Pool name. - * @param increment_size Increment size. - * @param callback Callback function. - */ -PJ_DECL(void) pj_pool_init_int( pj_pool_t *pool, - const char *name, - pj_size_t increment_size, - pj_pool_callback *callback); - -/** - * This function is intended to be used by pool factory implementors. - * @param pool The memory pool. - */ -PJ_DECL(void) pj_pool_destroy_int( pj_pool_t *pool ); - - -/** - * @} // PJ_POOL_FACTORY - */ - -/////////////////////////////////////////////////////////////////////////////// - -/** - * @defgroup PJ_CACHING_POOL Caching Pool Factory. - * @ingroup PJ_POOL_GROUP - * @brief - * Caching pool is one sample implementation of pool factory where the - * factory can reuse memory to create a pool. Application defines what the - * maximum memory the factory can hold, and when a pool is released the - * factory decides whether to destroy the pool or to keep it for future use. - * If the total amount of memory in the internal cache is still within the - * limit, the factory will keep the pool in the internal cache, otherwise the - * pool will be destroyed, thus releasing the memory back to the system. - * - * @{ - */ - -/** - * Number of unique sizes, to be used as index to the free list. - * Each pool in the free list is organized by it's size. - */ -#define PJ_CACHING_POOL_ARRAY_SIZE 16 - -/** - * Declaration for caching pool. Application doesn't normally need to - * care about the contents of this struct, it is only provided here because - * application need to define an instance of this struct (we can not allocate - * the struct from a pool since there is no pool factory yet!). - */ -struct pj_caching_pool -{ - /** Pool factory interface, must be declared first. */ - pj_pool_factory factory; - - /** Current factory's capacity, i.e. number of bytes that are allocated - * and available for application in this factory. The factory's - * capacity represents the size of all pools kept by this factory - * in it's free list, which will be returned to application when it - * requests to create a new pool. - */ - pj_size_t capacity; - - /** Maximum size that can be held by this factory. Once the capacity - * has exceeded @a max_capacity, further #pj_pool_release() will - * flush the pool. If the capacity is still below the @a max_capacity, - * #pj_pool_release() will save the pool to the factory's free list. - */ - pj_size_t max_capacity; - - /** - * Number of pools currently held by applications. This number gets - * incremented everytime #pj_pool_create() is called, and gets - * decremented when #pj_pool_release() is called. - */ - pj_size_t used_count; - - /** - * Lists of pools in the cache, indexed by pool size. - */ - pj_list free_list[PJ_CACHING_POOL_ARRAY_SIZE]; - - /** - * List of pools currently allocated by applications. - */ - pj_list used_list; -}; - - - -/** - * Initialize caching pool. - * - * @param ch_pool The caching pool factory to be initialized. - * @param policy Pool factory policy. - * @param max_capacity The total capacity to be retained in the cache. When - * the pool is returned to the cache, it will be kept in - * recycling list if the total capacity of pools in this - * list plus the capacity of the pool is still below this - * value. - */ -PJ_DECL(void) pj_caching_pool_init( pj_caching_pool *ch_pool, - const pj_pool_factory_policy *policy, - pj_size_t max_capacity); - - -/** - * Destroy caching pool, and release all the pools in the recycling list. - * - * @param ch_pool The caching pool. - */ -PJ_DECL(void) pj_caching_pool_destroy( pj_caching_pool *ch_pool ); - -/** - * @} // PJ_CACHING_POOL - */ - -# if PJ_FUNCTIONS_ARE_INLINED -# include "pool_i.h" -# endif - -PJ_END_DECL - -#endif /* __PJ_POOL_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/pool.h 10 10/14/05 12:26a Bennylp $ */ + +#ifndef __PJ_POOL_H__ +#define __PJ_POOL_H__ + +/** + * @file pool.h + * @brief Memory Pool. + */ + +#include + +PJ_BEGIN_DECL + +/** + * @defgroup PJ_POOL_GROUP Memory Pool Management + * @ingroup PJ + * @brief + * Memory pool management provides API to allocate and deallocate memory from + * memory pool and to manage and establish policy for pool creation and + * destruction in pool factory. + * + * \section PJ_POOL_FACTORY_SEC Pool Factory + * See: \ref PJ_POOL_FACTORY "Pool Factory" + * + * A memory pool must be created through a factory. A factory not only provides + * generic interface functions to create and release pool, but also provides + * strategy to manage the life time of pools. One sample implementation, + * \a pj_caching_pool, can be set to keep the pools released by application for + * future use as long as the total memory is below the limit. + * + * The pool factory interface declared in PJLIB is designed to be extensible. + * Application can define its own strategy by creating it's own pool factory + * implementation, and this strategy can be used even by existing library + * without recompilation. + * + * + * \section PJ_POOL_POLICY_SEC Pool Factory Policy + * See: \ref PJ_POOL_FACTORY "Pool Factory Policy" + * + * A pool factory only defines functions to create and release pool and how + * to manage pools, but the rest of the functionalities are controlled by + * policy. A pool policy defines: + * - how memory block is allocated and deallocated (the default implementation + * allocates and deallocate memory by calling malloc() and free()). + * - callback to be called when memory allocation inside a pool fails (the + * default implementation will throw PJ_NO_MEMORY_EXCEPTION exception). + * - concurrency when creating and releasing pool from/to the factory. + * + * A pool factory can be given different policy during creation to make + * it behave differently. For example, caching pool factory can be configured + * to allocate and deallocate from a static/contiguous/preallocated memory + * instead of using malloc()/free(). + * + * What strategy/factory and what policy to use is not defined by PJLIB, but + * instead is left to application to make use whichever is most efficient for + * itself. + * + * + * \section PJ_POOL_POOL_SEC The Pool + * See: \ref PJ_POOL "Pool" + * + * The memory pool is an opaque object created by pool factory. + * Application uses this object to request a memory chunk, by calling + * #pj_pool_alloc or #pj_pool_calloc. When the application has finished using + * the pool, it must call #pj_pool_release to free all the chunks previously + * allocated and release the pool back to the factory. + * + * \section PJ_POOL_THREADING_SEC More on Threading Policies: + * - By design, memory allocation from a pool is not thread safe. We assumed + * that a pool will be owned by an object, and thread safety should be + * handled by that object. Thus these functions are not thread safe: + * - #pj_pool_alloc, + * - #pj_pool_calloc, + * - and other pool statistic functions. + * - Threading in the pool factory is decided by the policy set for the + * factory when it was created. + * + * \section PJ_POOL_EXAMPLES_SEC Examples + * + * For some sample codes on how to use the pool, please see: + * - @ref page_pjlib_pool_test + */ + +/** + * @defgroup PJ_POOL Memory Pool. + * @ingroup PJ_POOL_GROUP + * @brief + * A memory pool is initialized with an initial amount of memory, which is + * called a block. Pool can be configured to dynamically allocate more memory + * blocks when it runs out of memory. Subsequent memory allocations by user + * will use up portions of these block. + * The pool doesn't keep track of individual memory allocations + * by user, and the user doesn't have to free these indidual allocations. This + * makes memory allocation simple and very fast. All the memory allocated from + * the pool will be destroyed when the pool itself is destroyed. + * @{ + */ + +/** + * The type for function to receive callback from the pool when it is unable + * to allocate memory. The elegant way to handle this condition is to throw + * exception, and this is what is expected by most of this library + * components. + */ +typedef void pj_pool_callback(pj_pool_t *pool, pj_size_t size); + +/** + * This class, which is used internally by the pool, describes a single + * block of memory from which user memory allocations will be allocated from. + */ +typedef struct pj_pool_block +{ + PJ_DECL_LIST_MEMBER(struct pj_pool_block) /**< List's prev and next. */ + unsigned char *buf; /**< Start of buffer. */ + unsigned char *cur; /**< Current alloc ptr. */ + unsigned char *end; /**< End of buffer. */ +} pj_pool_block; + + +/** + * This structure describes the memory pool. Only implementors of pool factory + * need to care about the contents of this structure. + */ +struct pj_pool_t +{ + PJ_DECL_LIST_MEMBER(struct pj_pool_t) + + /** Pool name */ + char obj_name[PJ_MAX_OBJ_NAME]; + + /** Pool factory. */ + pj_pool_factory *factory; + + /** Current capacity allocated by the pool. */ + pj_size_t capacity; + + /** Number of memory used/allocated. */ + pj_size_t used_size; + + /** Size of memory block to be allocated when the pool runs out of memory */ + pj_size_t increment_size; + + /** List of memory blocks allcoated by the pool. */ + pj_pool_block block_list; + + /** The callback to be called when the pool is unable to allocate memory. */ + pj_pool_callback *callback; + +}; + + +/** + * Guidance on how much memory required for initial pool administrative data. + */ +#define PJ_POOL_SIZE (sizeof(struct pj_pool_t)) + +/** + * Pool memory alignment (must be power of 2). + */ +#ifndef PJ_POOL_ALIGNMENT +# define PJ_POOL_ALIGNMENT 4 +#endif + +/** + * Create a new pool from the pool factory. This wrapper will call create_pool + * member of the pool factory. + * + * @param factory The pool factory. + * @param name The name to be assigned to the pool. The name should + * not be longer than PJ_MAX_OBJ_NAME (32 chars), or + * otherwise it will be truncated. + * @param initial_size The size of initial memory blocks taken by the pool. + * Note that the pool will take 68+20 bytes for + * administrative area from this block. + * @param increment_size the size of each additional blocks to be allocated + * when the pool is running out of memory. If user + * requests memory which is larger than this size, then + * an error occurs. + * Note that each time a pool allocates additional block, + * it needs PJ_POOL_SIZE more to store some + * administrative info. + * @param callback Callback to be called when error occurs in the pool. + * If this value is NULL, then the callback from pool + * factory policy will be used. + * Note that when an error occurs during pool creation, + * the callback itself is not called. Instead, NULL + * will be returned. + * + * @return The memory pool, or NULL. + */ +PJ_IDECL(pj_pool_t*) pj_pool_create(pj_pool_factory *factory, + const char *name, + pj_size_t initial_size, + pj_size_t increment_size, + pj_pool_callback *callback); + +/** + * Release the pool back to pool factory. + * + * @param pool Memory pool. + */ +PJ_IDECL(void) pj_pool_release( pj_pool_t *pool ); + +/** + * Get pool object name. + * + * @param pool the pool. + * + * @return pool name as NULL terminated string. + */ +PJ_IDECL(const char *) pj_pool_getobjname( const pj_pool_t *pool ); + +/** + * Reset the pool to its state when it was initialized. + * This means that if additional blocks have been allocated during runtime, + * then they will be freed. Only the original block allocated during + * initialization is retained. This function will also reset the internal + * counters, such as pool capacity and used size. + * + * @param pool the pool. + */ +PJ_DECL(void) pj_pool_reset( pj_pool_t *pool ); + + +/** + * Get the pool capacity, that is, the system storage that have been allocated + * by the pool, and have been used/will be used to allocate user requests. + * There's no guarantee that the returned value represent a single + * contiguous block, because the capacity may be spread in several blocks. + * + * @param pool the pool. + * + * @return the capacity. + */ +PJ_IDECL(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool ); + +/** + * Get the total size of user allocation request. + * + * @param pool the pool. + * + * @return the total size. + */ +PJ_IDECL(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool ); + +/** + * Allocate storage with the specified size from the pool. + * If there's no storage available in the pool, then the pool can allocate more + * blocks if the increment size is larger than the requested size. + * + * @param pool the pool. + * @param size the requested size. + * + * @return pointer to the allocated memory. + */ +PJ_IDECL(void*) pj_pool_alloc( pj_pool_t *pool, pj_size_t size); + +/** + * Allocate storage from the pool, and initialize it to zero. + * This function behaves like pj_pool_alloc(), except that the storage will + * be initialized to zero. + * + * @param pool the pool. + * @param count the number of elements in the array. + * @param elem the size of individual element. + * + * @return pointer to the allocated memory. + */ +PJ_IDECL(void*) pj_pool_calloc( pj_pool_t *pool, pj_size_t count, + pj_size_t elem); + + +/** + * @def pj_pool_zalloc(pj_pool_t *pool, pj_size_t size) + * Allocate storage from the pool and initialize it to zero. + * + * @param pool The pool. + * @param size The size to be allocated. + * + * @return Pointer to the allocated memory. + */ +#define pj_pool_zalloc(pool, size) pj_pool_calloc(pool, 1, size) + + +/** + * @} // PJ_POOL + */ + +/////////////////////////////////////////////////////////////////////////////// +/** + * @defgroup PJ_POOL_FACTORY Pool Factory and Policy. + * @ingroup PJ_POOL_GROUP + * @brief + * Pool factory declares an interface to create and destroy pool. There may + * be several strategies for pool creation, and these strategies should + * implement the interface defined by pool factory. + * + * \section PJ_POOL_FACTORY_ITF Pool Factory Interface + * The pool factory defines the following interface: + * - \a policy: the memory pool factory policy. + * - \a create_pool(): create a new memory pool. + * - \a release_pool(): release memory pool back to factory. + * + * \section PJ_POOL_FACTORY_POL Pool Factory Policy. + * The pool factory policy controls the behaviour of memory factories, and + * defines the following interface: + * - \a block_alloc(): allocate memory block from backend memory mgmt/system. + * - \a block_free(): free memory block back to backend memory mgmt/system. + * @{ + */ + +/* We unfortunately don't have support for factory policy options as now, + so we keep this commented at the moment. +enum PJ_POOL_FACTORY_OPTION +{ + PJ_POOL_FACTORY_SERIALIZE = 1 +}; +*/ + +/** + * This structure declares pool factory interface. + */ +typedef struct pj_pool_factory_policy +{ + /** + * Allocate memory block (for use by pool). This function is called + * by memory pool to allocate memory block. + * + * @param factory Pool factory. + * @param size The size of memory block to allocate. + * + * @return Memory block. + */ + void* (*block_alloc)(pj_pool_factory *factory, pj_size_t size); + + /** + * Free memory block. + * + * @param factory Pool factory. + * @param mem Memory block previously allocated by block_alloc(). + * @param size The size of memory block. + */ + void (*block_free)(pj_pool_factory *factory, void *mem, pj_size_t size); + + /** + * Default callback to be called when memory allocation fails. + */ + pj_pool_callback *callback; + + /** + * Option flags. + */ + unsigned flags; + +} pj_pool_factory_policy; + +/** + * This constant denotes the exception number that will be thrown by default + * memory factory policy when memory allocation fails. + */ +extern int PJ_NO_MEMORY_EXCEPTION; + +/** + * This global variable points to default memory pool factory policy. + * The behaviour of the default policy is: + * - block allocation and deallocation use malloc() and free(). + * - callback will raise PJ_NO_MEMORY_EXCEPTION exception. + * - access to pool factory is not serialized (i.e. not thread safe). + */ +extern pj_pool_factory_policy pj_pool_factory_default_policy; + +/** + * This structure contains the declaration for pool factory interface. + */ +struct pj_pool_factory +{ + /** + * Memory pool policy. + */ + pj_pool_factory_policy policy; + + /** + * Create a new pool from the pool factory. + * + * @param factory The pool factory. + * @param name the name to be assigned to the pool. The name should + * not be longer than PJ_MAX_OBJ_NAME (32 chars), or + * otherwise it will be truncated. + * @param initial_size the size of initial memory blocks taken by the pool. + * Note that the pool will take 68+20 bytes for + * administrative area from this block. + * @param increment_size the size of each additional blocks to be allocated + * when the pool is running out of memory. If user + * requests memory which is larger than this size, then + * an error occurs. + * Note that each time a pool allocates additional block, + * it needs 20 bytes (equal to sizeof(pj_pool_block)) to + * store some administrative info. + * @param callback Cllback to be called when error occurs in the pool. + * Note that when an error occurs during pool creation, + * the callback itself is not called. Instead, NULL + * will be returned. + * + * @return the memory pool, or NULL. + */ + pj_pool_t* (*create_pool)( pj_pool_factory *factory, + const char *name, + pj_size_t initial_size, + pj_size_t increment_size, + pj_pool_callback *callback); + + /** + * Release the pool to the pool factory. + * + * @param factory The pool factory. + * @param pool The pool to be released. + */ + void (*release_pool)( pj_pool_factory *factory, pj_pool_t *pool ); + + /** + * Dump pool status to log. + * + * @param factory The pool factory. + */ + void (*dump_status)( pj_pool_factory *factory, pj_bool_t detail ); +}; + +/** + * This function is intended to be used by pool factory implementors. + * @param factory Pool factory. + * @param name Pool name. + * @param initial_size Initial size. + * @param increment_size Increment size. + * @param callback Callback. + * @return The pool object, or NULL. + */ +PJ_DECL(pj_pool_t*) pj_pool_create_int( pj_pool_factory *factory, + const char *name, + pj_size_t initial_size, + pj_size_t increment_size, + pj_pool_callback *callback); + +/** + * This function is intended to be used by pool factory implementors. + * @param pool The pool. + * @param name Pool name. + * @param increment_size Increment size. + * @param callback Callback function. + */ +PJ_DECL(void) pj_pool_init_int( pj_pool_t *pool, + const char *name, + pj_size_t increment_size, + pj_pool_callback *callback); + +/** + * This function is intended to be used by pool factory implementors. + * @param pool The memory pool. + */ +PJ_DECL(void) pj_pool_destroy_int( pj_pool_t *pool ); + + +/** + * @} // PJ_POOL_FACTORY + */ + +/////////////////////////////////////////////////////////////////////////////// + +/** + * @defgroup PJ_CACHING_POOL Caching Pool Factory. + * @ingroup PJ_POOL_GROUP + * @brief + * Caching pool is one sample implementation of pool factory where the + * factory can reuse memory to create a pool. Application defines what the + * maximum memory the factory can hold, and when a pool is released the + * factory decides whether to destroy the pool or to keep it for future use. + * If the total amount of memory in the internal cache is still within the + * limit, the factory will keep the pool in the internal cache, otherwise the + * pool will be destroyed, thus releasing the memory back to the system. + * + * @{ + */ + +/** + * Number of unique sizes, to be used as index to the free list. + * Each pool in the free list is organized by it's size. + */ +#define PJ_CACHING_POOL_ARRAY_SIZE 16 + +/** + * Declaration for caching pool. Application doesn't normally need to + * care about the contents of this struct, it is only provided here because + * application need to define an instance of this struct (we can not allocate + * the struct from a pool since there is no pool factory yet!). + */ +struct pj_caching_pool +{ + /** Pool factory interface, must be declared first. */ + pj_pool_factory factory; + + /** Current factory's capacity, i.e. number of bytes that are allocated + * and available for application in this factory. The factory's + * capacity represents the size of all pools kept by this factory + * in it's free list, which will be returned to application when it + * requests to create a new pool. + */ + pj_size_t capacity; + + /** Maximum size that can be held by this factory. Once the capacity + * has exceeded @a max_capacity, further #pj_pool_release() will + * flush the pool. If the capacity is still below the @a max_capacity, + * #pj_pool_release() will save the pool to the factory's free list. + */ + pj_size_t max_capacity; + + /** + * Number of pools currently held by applications. This number gets + * incremented everytime #pj_pool_create() is called, and gets + * decremented when #pj_pool_release() is called. + */ + pj_size_t used_count; + + /** + * Lists of pools in the cache, indexed by pool size. + */ + pj_list free_list[PJ_CACHING_POOL_ARRAY_SIZE]; + + /** + * List of pools currently allocated by applications. + */ + pj_list used_list; +}; + + + +/** + * Initialize caching pool. + * + * @param ch_pool The caching pool factory to be initialized. + * @param policy Pool factory policy. + * @param max_capacity The total capacity to be retained in the cache. When + * the pool is returned to the cache, it will be kept in + * recycling list if the total capacity of pools in this + * list plus the capacity of the pool is still below this + * value. + */ +PJ_DECL(void) pj_caching_pool_init( pj_caching_pool *ch_pool, + const pj_pool_factory_policy *policy, + pj_size_t max_capacity); + + +/** + * Destroy caching pool, and release all the pools in the recycling list. + * + * @param ch_pool The caching pool. + */ +PJ_DECL(void) pj_caching_pool_destroy( pj_caching_pool *ch_pool ); + +/** + * @} // PJ_CACHING_POOL + */ + +# if PJ_FUNCTIONS_ARE_INLINED +# include "pool_i.h" +# endif + +PJ_END_DECL + +#endif /* __PJ_POOL_H__ */ + diff --git a/pjlib/include/pj/pool_i.h b/pjlib/include/pj/pool_i.h index 08dd7ca9..a9982515 100644 --- a/pjlib/include/pj/pool_i.h +++ b/pjlib/include/pj/pool_i.h @@ -1,74 +1,74 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/pool_i.h 6 10/14/05 12:26a Bennylp $ */ - - -#include - -PJ_DECL(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size); - -PJ_IDEF(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool ) -{ - return pool->capacity; -} - -PJ_IDEF(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool ) -{ - return pool->used_size; -} - -PJ_IDEF(void*) pj_pool_alloc_from_block( pj_pool_t *pool, - pj_pool_block *block, pj_size_t size ) -{ - /* The operation below is valid for size==0. - * When size==0, the function will return the pointer to the pool - * memory address, but no memory will be allocated. - */ - if (size & (PJ_POOL_ALIGNMENT-1)) { - size &= ~(PJ_POOL_ALIGNMENT-1); - size += PJ_POOL_ALIGNMENT; - } - if ((unsigned)(block->end - block->cur) >= size) { - void *ptr = block->cur; - block->cur += size; - pool->used_size += size; - return ptr; - } - return NULL; -} - -PJ_IDEF(void*) pj_pool_alloc( pj_pool_t *pool, pj_size_t size) -{ - pj_pool_block *block = pool->block_list.next; - void *ptr = pj_pool_alloc_from_block(pool, block, size); - if (!ptr) - ptr = pj_pool_allocate_find(pool, size); - return ptr; -} - - -PJ_IDEF(void*) pj_pool_calloc( pj_pool_t *pool, pj_size_t count, pj_size_t size) -{ - void *buf = pj_pool_alloc( pool, size*count); - if (buf) - pj_memset(buf, 0, size * count); - return buf; -} - -PJ_IDEF(const char *) pj_pool_getobjname( const pj_pool_t *pool ) -{ - return pool->obj_name; -} - -PJ_IDEF(pj_pool_t*) pj_pool_create( pj_pool_factory *f, - const char *name, - pj_size_t initial_size, - pj_size_t increment_size, - pj_pool_callback *callback) -{ - return (*f->create_pool)(f, name, initial_size, increment_size, callback); -} - -PJ_IDEF(void) pj_pool_release( pj_pool_t *pool ) -{ - (*pool->factory->release_pool)(pool->factory, pool); -} - +/* $Header: /pjproject-0.3/pjlib/include/pj/pool_i.h 6 10/14/05 12:26a Bennylp $ */ + + +#include + +PJ_DECL(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size); + +PJ_IDEF(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool ) +{ + return pool->capacity; +} + +PJ_IDEF(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool ) +{ + return pool->used_size; +} + +PJ_IDEF(void*) pj_pool_alloc_from_block( pj_pool_t *pool, + pj_pool_block *block, pj_size_t size ) +{ + /* The operation below is valid for size==0. + * When size==0, the function will return the pointer to the pool + * memory address, but no memory will be allocated. + */ + if (size & (PJ_POOL_ALIGNMENT-1)) { + size &= ~(PJ_POOL_ALIGNMENT-1); + size += PJ_POOL_ALIGNMENT; + } + if ((unsigned)(block->end - block->cur) >= size) { + void *ptr = block->cur; + block->cur += size; + pool->used_size += size; + return ptr; + } + return NULL; +} + +PJ_IDEF(void*) pj_pool_alloc( pj_pool_t *pool, pj_size_t size) +{ + pj_pool_block *block = pool->block_list.next; + void *ptr = pj_pool_alloc_from_block(pool, block, size); + if (!ptr) + ptr = pj_pool_allocate_find(pool, size); + return ptr; +} + + +PJ_IDEF(void*) pj_pool_calloc( pj_pool_t *pool, pj_size_t count, pj_size_t size) +{ + void *buf = pj_pool_alloc( pool, size*count); + if (buf) + pj_memset(buf, 0, size * count); + return buf; +} + +PJ_IDEF(const char *) pj_pool_getobjname( const pj_pool_t *pool ) +{ + return pool->obj_name; +} + +PJ_IDEF(pj_pool_t*) pj_pool_create( pj_pool_factory *f, + const char *name, + pj_size_t initial_size, + pj_size_t increment_size, + pj_pool_callback *callback) +{ + return (*f->create_pool)(f, name, initial_size, increment_size, callback); +} + +PJ_IDEF(void) pj_pool_release( pj_pool_t *pool ) +{ + (*pool->factory->release_pool)(pool->factory, pool); +} + diff --git a/pjlib/include/pj/rand.h b/pjlib/include/pj/rand.h index 2f612319..4a0bb801 100644 --- a/pjlib/include/pj/rand.h +++ b/pjlib/include/pj/rand.h @@ -1,60 +1,60 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/rand.h 3 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/include/pj/rand.h $ - * - * 3 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - * 1 9/15/05 8:40p Bennylp - * Created. - */ -#ifndef __PJ_RAND_H__ -#define __PJ_RAND_H__ - -/** - * @file rand.h - * @brief Random Number Generator. - */ - -#include - -PJ_BEGIN_DECL - - -/** - * @defgroup PJ_RAND Random Number Generator - * @ingroup PJ_MISC - * @{ - * This module contains functions for generating random numbers. - * This abstraction is needed not only because not all platforms have - * \a rand() and \a srand(), but also on some platforms \a rand() - * only has 16-bit randomness, which is not good enough. - */ - -/** - * Put in seed to random number generator. - * - * @param seed Seed value. - */ -PJ_DECL(void) pj_srand(unsigned int seed); - - -/** - * Generate random integer with 32bit randomness. - * - * @return a random integer. - */ -PJ_DECL(int) pj_rand(void); - - -/** @} */ - - -PJ_END_DECL - - -#endif /* __PJ_RAND_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/rand.h 3 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/include/pj/rand.h $ + * + * 3 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 2 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + * 1 9/15/05 8:40p Bennylp + * Created. + */ +#ifndef __PJ_RAND_H__ +#define __PJ_RAND_H__ + +/** + * @file rand.h + * @brief Random Number Generator. + */ + +#include + +PJ_BEGIN_DECL + + +/** + * @defgroup PJ_RAND Random Number Generator + * @ingroup PJ_MISC + * @{ + * This module contains functions for generating random numbers. + * This abstraction is needed not only because not all platforms have + * \a rand() and \a srand(), but also on some platforms \a rand() + * only has 16-bit randomness, which is not good enough. + */ + +/** + * Put in seed to random number generator. + * + * @param seed Seed value. + */ +PJ_DECL(void) pj_srand(unsigned int seed); + + +/** + * Generate random integer with 32bit randomness. + * + * @return a random integer. + */ +PJ_DECL(int) pj_rand(void); + + +/** @} */ + + +PJ_END_DECL + + +#endif /* __PJ_RAND_H__ */ + diff --git a/pjlib/include/pj/rbtree.h b/pjlib/include/pj/rbtree.h index f94e3658..b0997680 100644 --- a/pjlib/include/pj/rbtree.h +++ b/pjlib/include/pj/rbtree.h @@ -1,193 +1,193 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/rbtree.h 5 10/14/05 12:26a Bennylp $ */ - -#ifndef __PJ_RBTREE_H__ -#define __PJ_RBTREE_H__ - -/** - * @file rbtree.h - * @brief Red/Black Tree - */ - -#include - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_RBTREE Red/Black Balanced Tree - * @ingroup PJ_DS - * @brief - * Red/Black tree is the variant of balanced tree, where the search, insert, - * and delete operation is \b guaranteed to take at most \a O( lg(n) ). - * @{ - */ -/** - * Color type for Red-Black tree. - */ -typedef enum pj_rbcolor_t -{ - PJ_RBCOLOR_BLACK, - PJ_RBCOLOR_RED -} pj_rbcolor_t; - -/** - * The type of the node of the R/B Tree. - */ -typedef struct pj_rbtree_node -{ - /** Pointers to the node's parent, and left and right siblings. */ - struct pj_rbtree_node *parent, *left, *right; - - /** Key associated with the node. */ - const void *key; - - /** User data associated with the node. */ - void *user_data; - - /** The R/B Tree node color. */ - pj_rbcolor_t color; - -} pj_rbtree_node; - - -/** - * The type of function use to compare key value of tree node. - * @return - * 0 if the keys are equal - * <0 if key1 is lower than key2 - * >0 if key1 is greater than key2. - */ -typedef int pj_rbtree_comp(const void *key1, const void *key2); - - -/** - * Declaration of a red-black tree. All elements in the tree must have UNIQUE - * key. - * A red black tree always maintains the balance of the tree, so that the - * tree height will not be greater than lg(N). Insert, search, and delete - * operation will take lg(N) on the worst case. But for insert and delete, - * there is additional time needed to maintain the balance of the tree. - */ -typedef struct pj_rbtree -{ - pj_rbtree_node null_node; /**< Constant to indicate NULL node. */ - pj_rbtree_node *null; /**< Constant to indicate NULL node. */ - pj_rbtree_node *root; /**< Root tree node. */ - unsigned size; /**< Number of elements in the tree. */ - pj_rbtree_comp *comp; /**< Key comparison function. */ -} pj_rbtree; - - -/** - * Guidance on how much memory required for each of the node. - */ -#define PJ_RBTREE_NODE_SIZE (sizeof(pj_rbtree_node)) - - -/** - * Guidance on memory required for the tree. - */ -#define PJ_RBTREE_SIZE (sizeof(pj_rbtree)) - - -/** - * Initialize the tree. - * @param tree the tree to be initialized. - * @param comp key comparison function to be used for this tree. - */ -PJ_DECL(void) pj_rbtree_init( pj_rbtree *tree, pj_rbtree_comp *comp); - -/** - * Get the first element in the tree. - * The first element always has the least value for the key, according to - * the comparison function. - * @param tree the tree. - * @return the tree node, or NULL if the tree has no element. - */ -PJ_DECL(pj_rbtree_node*) pj_rbtree_first( pj_rbtree *tree ); - -/** - * Get the last element in the tree. - * The last element always has the greatest key value, according to the - * comparison function defined for the tree. - * @param tree the tree. - * @return the tree node, or NULL if the tree has no element. - */ -PJ_DECL(pj_rbtree_node*) pj_rbtree_last( pj_rbtree *tree ); - -/** - * Get the successive element for the specified node. - * The successive element is an element with greater key value. - * @param tree the tree. - * @param node the node. - * @return the successive node, or NULL if the node has no successor. - */ -PJ_DECL(pj_rbtree_node*) pj_rbtree_next( pj_rbtree *tree, - pj_rbtree_node *node ); - -/** - * The the previous node for the specified node. - * The previous node is an element with less key value. - * @param tree the tree. - * @param node the node. - * @return the previous node, or NULL if the node has no previous node. - */ -PJ_DECL(pj_rbtree_node*) pj_rbtree_prev( pj_rbtree *tree, - pj_rbtree_node *node ); - -/** - * Insert a new node. - * The node will be inserted at sorted location. The key of the node must - * be UNIQUE, i.e. it hasn't existed in the tree. - * @param tree the tree. - * @param node the node to be inserted. - * @return zero on success, or -1 if the key already exist. - */ -PJ_DECL(int) pj_rbtree_insert( pj_rbtree *tree, - pj_rbtree_node *node ); - -/** - * Find a node which has the specified key. - * @param tree the tree. - * @param key the key to search. - * @return the tree node with the specified key, or NULL if the key can not - * be found. - */ -PJ_DECL(pj_rbtree_node*) pj_rbtree_find( pj_rbtree *tree, - const void *key ); - -/** - * Erase a node from the tree. - * @param tree the tree. - * @param node the node to be erased. - * @return the tree node itself. - */ -PJ_DECL(pj_rbtree_node*) pj_rbtree_erase( pj_rbtree *tree, - pj_rbtree_node *node ); - -/** - * Get the maximum tree height from the specified node. - * @param tree the tree. - * @param node the node, or NULL to get the root of the tree. - * @return the maximum height, which should be at most lg(N) - */ -PJ_DECL(unsigned) pj_rbtree_max_height( pj_rbtree *tree, - pj_rbtree_node *node ); - -/** - * Get the minumum tree height from the specified node. - * @param tree the tree. - * @param node the node, or NULL to get the root of the tree. - * @return the height - */ -PJ_DECL(unsigned) pj_rbtree_min_height( pj_rbtree *tree, - pj_rbtree_node *node ); - - -/** - * @} - */ - -PJ_END_DECL - -#endif /* __PJ_RBTREE_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/rbtree.h 5 10/14/05 12:26a Bennylp $ */ + +#ifndef __PJ_RBTREE_H__ +#define __PJ_RBTREE_H__ + +/** + * @file rbtree.h + * @brief Red/Black Tree + */ + +#include + +PJ_BEGIN_DECL + +/** + * @defgroup PJ_RBTREE Red/Black Balanced Tree + * @ingroup PJ_DS + * @brief + * Red/Black tree is the variant of balanced tree, where the search, insert, + * and delete operation is \b guaranteed to take at most \a O( lg(n) ). + * @{ + */ +/** + * Color type for Red-Black tree. + */ +typedef enum pj_rbcolor_t +{ + PJ_RBCOLOR_BLACK, + PJ_RBCOLOR_RED +} pj_rbcolor_t; + +/** + * The type of the node of the R/B Tree. + */ +typedef struct pj_rbtree_node +{ + /** Pointers to the node's parent, and left and right siblings. */ + struct pj_rbtree_node *parent, *left, *right; + + /** Key associated with the node. */ + const void *key; + + /** User data associated with the node. */ + void *user_data; + + /** The R/B Tree node color. */ + pj_rbcolor_t color; + +} pj_rbtree_node; + + +/** + * The type of function use to compare key value of tree node. + * @return + * 0 if the keys are equal + * <0 if key1 is lower than key2 + * >0 if key1 is greater than key2. + */ +typedef int pj_rbtree_comp(const void *key1, const void *key2); + + +/** + * Declaration of a red-black tree. All elements in the tree must have UNIQUE + * key. + * A red black tree always maintains the balance of the tree, so that the + * tree height will not be greater than lg(N). Insert, search, and delete + * operation will take lg(N) on the worst case. But for insert and delete, + * there is additional time needed to maintain the balance of the tree. + */ +typedef struct pj_rbtree +{ + pj_rbtree_node null_node; /**< Constant to indicate NULL node. */ + pj_rbtree_node *null; /**< Constant to indicate NULL node. */ + pj_rbtree_node *root; /**< Root tree node. */ + unsigned size; /**< Number of elements in the tree. */ + pj_rbtree_comp *comp; /**< Key comparison function. */ +} pj_rbtree; + + +/** + * Guidance on how much memory required for each of the node. + */ +#define PJ_RBTREE_NODE_SIZE (sizeof(pj_rbtree_node)) + + +/** + * Guidance on memory required for the tree. + */ +#define PJ_RBTREE_SIZE (sizeof(pj_rbtree)) + + +/** + * Initialize the tree. + * @param tree the tree to be initialized. + * @param comp key comparison function to be used for this tree. + */ +PJ_DECL(void) pj_rbtree_init( pj_rbtree *tree, pj_rbtree_comp *comp); + +/** + * Get the first element in the tree. + * The first element always has the least value for the key, according to + * the comparison function. + * @param tree the tree. + * @return the tree node, or NULL if the tree has no element. + */ +PJ_DECL(pj_rbtree_node*) pj_rbtree_first( pj_rbtree *tree ); + +/** + * Get the last element in the tree. + * The last element always has the greatest key value, according to the + * comparison function defined for the tree. + * @param tree the tree. + * @return the tree node, or NULL if the tree has no element. + */ +PJ_DECL(pj_rbtree_node*) pj_rbtree_last( pj_rbtree *tree ); + +/** + * Get the successive element for the specified node. + * The successive element is an element with greater key value. + * @param tree the tree. + * @param node the node. + * @return the successive node, or NULL if the node has no successor. + */ +PJ_DECL(pj_rbtree_node*) pj_rbtree_next( pj_rbtree *tree, + pj_rbtree_node *node ); + +/** + * The the previous node for the specified node. + * The previous node is an element with less key value. + * @param tree the tree. + * @param node the node. + * @return the previous node, or NULL if the node has no previous node. + */ +PJ_DECL(pj_rbtree_node*) pj_rbtree_prev( pj_rbtree *tree, + pj_rbtree_node *node ); + +/** + * Insert a new node. + * The node will be inserted at sorted location. The key of the node must + * be UNIQUE, i.e. it hasn't existed in the tree. + * @param tree the tree. + * @param node the node to be inserted. + * @return zero on success, or -1 if the key already exist. + */ +PJ_DECL(int) pj_rbtree_insert( pj_rbtree *tree, + pj_rbtree_node *node ); + +/** + * Find a node which has the specified key. + * @param tree the tree. + * @param key the key to search. + * @return the tree node with the specified key, or NULL if the key can not + * be found. + */ +PJ_DECL(pj_rbtree_node*) pj_rbtree_find( pj_rbtree *tree, + const void *key ); + +/** + * Erase a node from the tree. + * @param tree the tree. + * @param node the node to be erased. + * @return the tree node itself. + */ +PJ_DECL(pj_rbtree_node*) pj_rbtree_erase( pj_rbtree *tree, + pj_rbtree_node *node ); + +/** + * Get the maximum tree height from the specified node. + * @param tree the tree. + * @param node the node, or NULL to get the root of the tree. + * @return the maximum height, which should be at most lg(N) + */ +PJ_DECL(unsigned) pj_rbtree_max_height( pj_rbtree *tree, + pj_rbtree_node *node ); + +/** + * Get the minumum tree height from the specified node. + * @param tree the tree. + * @param node the node, or NULL to get the root of the tree. + * @return the height + */ +PJ_DECL(unsigned) pj_rbtree_min_height( pj_rbtree *tree, + pj_rbtree_node *node ); + + +/** + * @} + */ + +PJ_END_DECL + +#endif /* __PJ_RBTREE_H__ */ + diff --git a/pjlib/include/pj/scanner.h b/pjlib/include/pj/scanner.h index 5b04c687..5a82ff91 100644 --- a/pjlib/include/pj/scanner.h +++ b/pjlib/include/pj/scanner.h @@ -1,454 +1,454 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/scanner.h 10 10/14/05 12:26a Bennylp $ */ - -#ifndef __PJ_PARSER_H__ -#define __PJ_PARSER_H__ - -/** - * @file scanner.h - * @brief Text Scanning. - */ - -#include - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_SCAN Text Scanning - * @ingroup PJ_MISC - * @brief - * Text scanning utility. - */ - -/** - * @defgroup PJ_CHARSPEC Character Filter Specification - * @ingroup PJ_SCAN - * @brief - * The type pj_char_spec is a specification of character set used in - * scanner. Application can define multiple character specs, such as to - * scan alpha numerics, numbers, tokens, etc. - * @{ - */ - -/** - * This describes the type of individual character specification in - * #pj_char_spec. - */ -typedef pj_uint8_t pj_char_spec_element_t; - -/** - * The character specification is implemented as array of boolean flags. Each - * flag indicates the membership of the character in the spec. If the flag - * at one position is non-zero, then the character at that position belongs - * to the specification, and vice versa. - */ -typedef pj_char_spec_element_t pj_char_spec[256]; -// Note: it's got to be 256 (not 128) to cater for extended character in input. - -/** - * Initialize character spec. - * @param cs the scanner character specification. - */ -PJ_DECL(void) pj_cs_init( pj_char_spec cs); - -/** - * Set the membership of the specified character to TRUE. - * @param cs the scanner character specification. - * @param c the character. - */ -PJ_DECL(void) pj_cs_set( pj_char_spec cs, int c); - -/** - * Add the characters in the specified range '[cstart, cend)' to the - * specification (the last character itself ('cend') is not added). - * @param cs the scanner character specification. - * @param cstart the first character in the range. - * @param cend the next character after the last character in the range. - */ -PJ_DECL(void) pj_cs_add_range( pj_char_spec cs, int cstart, int cend); - -/** - * Add alphabetic characters to the specification. - * @param cs the scanner character specification. - */ -PJ_DECL(void) pj_cs_add_alpha( pj_char_spec cs); - -/** - * Add numeric characters to the specification. - * @param cs the scanner character specification. - */ -PJ_DECL(void) pj_cs_add_num( pj_char_spec cs); - -/** - * Add the characters in the string to the specification. - * @param cs the scanner character specification. - * @param str the string. - */ -PJ_DECL(void) pj_cs_add_str( pj_char_spec cs, const char *str); - -/** - * Delete characters in the specified range from the specification. - * @param cs the scanner character specification. - * @param cstart the first character in the range. - * @param cend the next character after the last character in the range. - */ -PJ_DECL(void) pj_cs_del_range( pj_char_spec cs, int cstart, int cend); - -/** - * Delete characters in the specified string from the specification. - * @param cs the scanner character specification. - * @param str the string. - */ -PJ_DECL(void) pj_cs_del_str( pj_char_spec cs, const char *str); - -/** - * Invert specification. - * @param cs the scanner character specification. - */ -PJ_DECL(void) pj_cs_invert( pj_char_spec cs ); - -/** - * Check whether the specified character belongs to the specification. - * @param cs the scanner character specification. - * @param c the character to check for matching. - */ -PJ_INLINE(int) pj_cs_match( const pj_char_spec cs, int c ) -{ - return cs[c]; -} - -/** - * @} - */ - -/** - * @defgroup PJ_SCANNER Text Scanner - * @ingroup PJ_SCAN - * @{ - */ - -/** - * Flags for scanner. - */ -enum -{ - /** This flags specifies that the scanner should automatically skip - whitespaces - */ - PJ_SCAN_AUTOSKIP_WS = 1, - - /** This flags specifies that the scanner should automatically skip - SIP header continuation. This flag implies PJ_SCAN_AUTOSKIP_WS. - */ - PJ_SCAN_AUTOSKIP_WS_HEADER = 3, - - /** Auto-skip new lines. - */ - PJ_SCAN_AUTOSKIP_NEWLINE = 4, -}; - - -/* Forward decl. */ -struct pj_scanner; - - -/** - * The callback function type to be called by the scanner when it encounters - * syntax error. - * @param scanner The scanner instance that calls the callback . - */ -typedef void (*pj_syn_err_func_ptr)(struct pj_scanner *scanner); - - -/** - * The text scanner structure. - */ -typedef struct pj_scanner -{ - char *begin; /**< Start of input buffer. */ - char *end; /**< End of input buffer. */ - char *curptr; /**< Current pointer. */ - int line; /**< Current line. */ - int col; /**< Current column. */ - int skip_ws; /**< Skip whitespace flag. */ - pj_syn_err_func_ptr callback; /**< Syntax error callback. */ -} pj_scanner; - - -/** - * This structure can be used by application to store the state of the parser, - * so that the scanner state can be rollback to this state when necessary. - */ -typedef struct pj_scan_state -{ - char *curptr; /**< Current scanner's pointer. */ - int line; /**< Current line. */ - int col; /**< Current column. */ -} pj_scan_state; - - -/** - * Initialize the scanner. Note that the input string buffer must have - * length at least buflen+1 because the scanner will NULL terminate the - * string during initialization. - * - * @param scanner The scanner to be initialized. - * @param bufstart The input buffer to scan. Note that buffer[buflen] will be - * filled with NULL char until scanner is destroyed, so - * the actual buffer length must be at least buflen+1. - * @param buflen The length of the input buffer, which normally is - * strlen(bufstart). - * @param options Zero, or combination of PJ_SCAN_AUTOSKIP_WS or - * PJ_SCAN_AUTOSKIP_WS_HEADER - * @param callback Callback to be called when the scanner encounters syntax - * error condition. - */ -PJ_DECL(void) pj_scan_init( pj_scanner *scanner, char *bufstart, int buflen, - unsigned options, - pj_syn_err_func_ptr callback ); - - -/** - * Call this function when application has finished using the scanner. - * - * @param scanner The scanner. - */ -PJ_DECL(void) pj_scan_fini( pj_scanner *scanner ); - - -/** - * Determine whether the EOF condition for the scanner has been met. - * - * @param scanner The scanner. - * - * @return Non-zero if scanner is EOF. - */ -PJ_INLINE(int) pj_scan_is_eof( const pj_scanner *scanner) -{ - return scanner->curptr >= scanner->end; -} - - -/** - * Peek strings in current position according to parameter spec, and return - * the strings in parameter out. The current scanner position will not be - * moved. If the scanner is already in EOF state, syntax error callback will - * be called thrown. - * - * @param scanner The scanner. - * @param spec The spec to match input string. - * @param out String to store the result. - * - * @return the character right after the peek-ed position or zero if there's - * no more characters. - */ -PJ_DECL(int) pj_scan_peek( pj_scanner *scanner, - const pj_char_spec spec, pj_str_t *out); - - -/** - * Peek len characters in current position, and return them in out parameter. - * Note that whitespaces or newlines will be returned as it is, regardless - * of PJ_SCAN_AUTOSKIP_WS settings. If the character left is less than len, - * syntax error callback will be called. - * - * @param scanner The scanner. - * @param len Length to peek. - * @param out String to store the result. - * - * @return the character right after the peek-ed position or zero if there's - * no more characters. - */ -PJ_DECL(int) pj_scan_peek_n( pj_scanner *scanner, - pj_size_t len, pj_str_t *out); - - -/** - * Peek strings in current position until spec is matched, and return - * the strings in parameter out. The current scanner position will not be - * moved. If the scanner is already in EOF state, syntax error callback will - * be called. - * - * @param scanner The scanner. - * @param spec The peeking will stop when the input match this spec. - * @param out String to store the result. - * - * @return the character right after the peek-ed position. - */ -PJ_DECL(int) pj_scan_peek_until( pj_scanner *scanner, - const pj_char_spec spec, - pj_str_t *out); - - -/** - * Get characters from the buffer according to the spec, and return them - * in out parameter. The scanner will attempt to get as many characters as - * possible as long as the spec matches. If the first character doesn't - * match the spec, or scanner is already in EOF when this function is called, - * an exception will be thrown. - * - * @param scanner The scanner. - * @param spec The spec to match input string. - * @param out String to store the result. - */ -PJ_DECL(void) pj_scan_get( pj_scanner *scanner, - const pj_char_spec spec, pj_str_t *out); - - -/** - * Get characters between quotes. If current input doesn't match begin_quote, - * syntax error will be thrown. - * - * @param scanner The scanner. - * @param begin_quote The character to begin the quote. - * @param end_quote The character to end the quote. - * @param out String to store the result. - */ -PJ_DECL(void) pj_scan_get_quote( pj_scanner *scanner, - int begin_quote, int end_quote, - pj_str_t *out); - -/** - * Get N characters from the scanner. - * - * @param scanner The scanner. - * @param N Number of characters to get. - * @param out String to store the result. - */ -PJ_DECL(void) pj_scan_get_n( pj_scanner *scanner, - unsigned N, pj_str_t *out); - - -/** - * Get one character from the scanner. - * - * @param scanner The scanner. - * - * @return (unknown) - */ -PJ_DECL(int) pj_scan_get_char( pj_scanner *scanner ); - - -/** - * Get a newline from the scanner. A newline is defined as '\\n', or '\\r', or - * "\\r\\n". If current input is not newline, syntax error will be thrown. - * - * @param scanner The scanner. - */ -PJ_DECL(void) pj_scan_get_newline( pj_scanner *scanner ); - - -/** - * Get characters from the scanner and move the scanner position until the - * current character matches the spec. - * - * @param scanner The scanner. - * @param spec Get until the input match this spec. - * @param out String to store the result. - */ -PJ_DECL(void) pj_scan_get_until( pj_scanner *scanner, - const pj_char_spec spec, pj_str_t *out); - - -/** - * Get characters from the scanner and move the scanner position until the - * current character matches until_char. - * - * @param scanner The scanner. - * @param until_char Get until the input match this character. - * @param out String to store the result. - */ -PJ_DECL(void) pj_scan_get_until_ch( pj_scanner *scanner, - int until_char, pj_str_t *out); - - -/** - * Get characters from the scanner and move the scanner position until the - * current character matches until_char. - * - * @param scanner The scanner. - * @param until_spec Get until the input match any of these characters. - * @param out String to store the result. - */ -PJ_DECL(void) pj_scan_get_until_chr( pj_scanner *scanner, - const char *until_spec, pj_str_t *out); - -/** - * Advance the scanner N characters, and skip whitespace - * if necessary. - * - * @param scanner The scanner. - * @param N Number of characters to skip. - * @param skip Flag to specify whether whitespace should be skipped - * after skipping the characters. - */ -PJ_DECL(void) pj_scan_advance_n( pj_scanner *scanner, - unsigned N, pj_bool_t skip); - - -/** - * Compare string in current position with the specified string. - * - * @param scanner The scanner. - * @param s The string to compare with. - * @param len Length of the string to compare. - * - * @return zero, <0, or >0 (just like strcmp()). - */ -PJ_DECL(int) pj_scan_strcmp( pj_scanner *scanner, const char *s, int len); - - -/** - * Case-less string comparison of current position with the specified - * string. - * - * @param scanner The scanner. - * @param s The string to compare with. - * @param len Length of the string to compare with. - * - * @return zero, <0, or >0 (just like strcmp()). - */ -PJ_DECL(int) pj_scan_stricmp( pj_scanner *scanner, const char *s, int len); - - -/** - * Manually skip whitespaces according to flag that was specified when - * the scanner was initialized. - * - * @param scanner The scanner. - */ -PJ_DECL(void) pj_scan_skip_whitespace( pj_scanner *scanner ); - - -/** - * Save the full scanner state. - * - * @param scanner The scanner. - * @param state Variable to store scanner's state. - */ -PJ_DECL(void) pj_scan_save_state( pj_scanner *scanner, pj_scan_state *state); - - -/** - * Restore the full scanner state. - * Note that this would not restore the string if application has modified - * it. This will only restore the scanner scanning position. - * - * @param scanner The scanner. - * @param state State of the scanner. - */ -PJ_DECL(void) pj_scan_restore_state( pj_scanner *scanner, - pj_scan_state *state); - -/** - * @} - */ - -#if PJ_FUNCTIONS_ARE_INLINED -# include "scanner_i.h" -#endif - - -PJ_END_DECL - -#endif - +/* $Header: /pjproject-0.3/pjlib/include/pj/scanner.h 10 10/14/05 12:26a Bennylp $ */ + +#ifndef __PJ_PARSER_H__ +#define __PJ_PARSER_H__ + +/** + * @file scanner.h + * @brief Text Scanning. + */ + +#include + +PJ_BEGIN_DECL + +/** + * @defgroup PJ_SCAN Text Scanning + * @ingroup PJ_MISC + * @brief + * Text scanning utility. + */ + +/** + * @defgroup PJ_CHARSPEC Character Filter Specification + * @ingroup PJ_SCAN + * @brief + * The type pj_char_spec is a specification of character set used in + * scanner. Application can define multiple character specs, such as to + * scan alpha numerics, numbers, tokens, etc. + * @{ + */ + +/** + * This describes the type of individual character specification in + * #pj_char_spec. + */ +typedef pj_uint8_t pj_char_spec_element_t; + +/** + * The character specification is implemented as array of boolean flags. Each + * flag indicates the membership of the character in the spec. If the flag + * at one position is non-zero, then the character at that position belongs + * to the specification, and vice versa. + */ +typedef pj_char_spec_element_t pj_char_spec[256]; +// Note: it's got to be 256 (not 128) to cater for extended character in input. + +/** + * Initialize character spec. + * @param cs the scanner character specification. + */ +PJ_DECL(void) pj_cs_init( pj_char_spec cs); + +/** + * Set the membership of the specified character to TRUE. + * @param cs the scanner character specification. + * @param c the character. + */ +PJ_DECL(void) pj_cs_set( pj_char_spec cs, int c); + +/** + * Add the characters in the specified range '[cstart, cend)' to the + * specification (the last character itself ('cend') is not added). + * @param cs the scanner character specification. + * @param cstart the first character in the range. + * @param cend the next character after the last character in the range. + */ +PJ_DECL(void) pj_cs_add_range( pj_char_spec cs, int cstart, int cend); + +/** + * Add alphabetic characters to the specification. + * @param cs the scanner character specification. + */ +PJ_DECL(void) pj_cs_add_alpha( pj_char_spec cs); + +/** + * Add numeric characters to the specification. + * @param cs the scanner character specification. + */ +PJ_DECL(void) pj_cs_add_num( pj_char_spec cs); + +/** + * Add the characters in the string to the specification. + * @param cs the scanner character specification. + * @param str the string. + */ +PJ_DECL(void) pj_cs_add_str( pj_char_spec cs, const char *str); + +/** + * Delete characters in the specified range from the specification. + * @param cs the scanner character specification. + * @param cstart the first character in the range. + * @param cend the next character after the last character in the range. + */ +PJ_DECL(void) pj_cs_del_range( pj_char_spec cs, int cstart, int cend); + +/** + * Delete characters in the specified string from the specification. + * @param cs the scanner character specification. + * @param str the string. + */ +PJ_DECL(void) pj_cs_del_str( pj_char_spec cs, const char *str); + +/** + * Invert specification. + * @param cs the scanner character specification. + */ +PJ_DECL(void) pj_cs_invert( pj_char_spec cs ); + +/** + * Check whether the specified character belongs to the specification. + * @param cs the scanner character specification. + * @param c the character to check for matching. + */ +PJ_INLINE(int) pj_cs_match( const pj_char_spec cs, int c ) +{ + return cs[c]; +} + +/** + * @} + */ + +/** + * @defgroup PJ_SCANNER Text Scanner + * @ingroup PJ_SCAN + * @{ + */ + +/** + * Flags for scanner. + */ +enum +{ + /** This flags specifies that the scanner should automatically skip + whitespaces + */ + PJ_SCAN_AUTOSKIP_WS = 1, + + /** This flags specifies that the scanner should automatically skip + SIP header continuation. This flag implies PJ_SCAN_AUTOSKIP_WS. + */ + PJ_SCAN_AUTOSKIP_WS_HEADER = 3, + + /** Auto-skip new lines. + */ + PJ_SCAN_AUTOSKIP_NEWLINE = 4, +}; + + +/* Forward decl. */ +struct pj_scanner; + + +/** + * The callback function type to be called by the scanner when it encounters + * syntax error. + * @param scanner The scanner instance that calls the callback . + */ +typedef void (*pj_syn_err_func_ptr)(struct pj_scanner *scanner); + + +/** + * The text scanner structure. + */ +typedef struct pj_scanner +{ + char *begin; /**< Start of input buffer. */ + char *end; /**< End of input buffer. */ + char *curptr; /**< Current pointer. */ + int line; /**< Current line. */ + int col; /**< Current column. */ + int skip_ws; /**< Skip whitespace flag. */ + pj_syn_err_func_ptr callback; /**< Syntax error callback. */ +} pj_scanner; + + +/** + * This structure can be used by application to store the state of the parser, + * so that the scanner state can be rollback to this state when necessary. + */ +typedef struct pj_scan_state +{ + char *curptr; /**< Current scanner's pointer. */ + int line; /**< Current line. */ + int col; /**< Current column. */ +} pj_scan_state; + + +/** + * Initialize the scanner. Note that the input string buffer must have + * length at least buflen+1 because the scanner will NULL terminate the + * string during initialization. + * + * @param scanner The scanner to be initialized. + * @param bufstart The input buffer to scan. Note that buffer[buflen] will be + * filled with NULL char until scanner is destroyed, so + * the actual buffer length must be at least buflen+1. + * @param buflen The length of the input buffer, which normally is + * strlen(bufstart). + * @param options Zero, or combination of PJ_SCAN_AUTOSKIP_WS or + * PJ_SCAN_AUTOSKIP_WS_HEADER + * @param callback Callback to be called when the scanner encounters syntax + * error condition. + */ +PJ_DECL(void) pj_scan_init( pj_scanner *scanner, char *bufstart, int buflen, + unsigned options, + pj_syn_err_func_ptr callback ); + + +/** + * Call this function when application has finished using the scanner. + * + * @param scanner The scanner. + */ +PJ_DECL(void) pj_scan_fini( pj_scanner *scanner ); + + +/** + * Determine whether the EOF condition for the scanner has been met. + * + * @param scanner The scanner. + * + * @return Non-zero if scanner is EOF. + */ +PJ_INLINE(int) pj_scan_is_eof( const pj_scanner *scanner) +{ + return scanner->curptr >= scanner->end; +} + + +/** + * Peek strings in current position according to parameter spec, and return + * the strings in parameter out. The current scanner position will not be + * moved. If the scanner is already in EOF state, syntax error callback will + * be called thrown. + * + * @param scanner The scanner. + * @param spec The spec to match input string. + * @param out String to store the result. + * + * @return the character right after the peek-ed position or zero if there's + * no more characters. + */ +PJ_DECL(int) pj_scan_peek( pj_scanner *scanner, + const pj_char_spec spec, pj_str_t *out); + + +/** + * Peek len characters in current position, and return them in out parameter. + * Note that whitespaces or newlines will be returned as it is, regardless + * of PJ_SCAN_AUTOSKIP_WS settings. If the character left is less than len, + * syntax error callback will be called. + * + * @param scanner The scanner. + * @param len Length to peek. + * @param out String to store the result. + * + * @return the character right after the peek-ed position or zero if there's + * no more characters. + */ +PJ_DECL(int) pj_scan_peek_n( pj_scanner *scanner, + pj_size_t len, pj_str_t *out); + + +/** + * Peek strings in current position until spec is matched, and return + * the strings in parameter out. The current scanner position will not be + * moved. If the scanner is already in EOF state, syntax error callback will + * be called. + * + * @param scanner The scanner. + * @param spec The peeking will stop when the input match this spec. + * @param out String to store the result. + * + * @return the character right after the peek-ed position. + */ +PJ_DECL(int) pj_scan_peek_until( pj_scanner *scanner, + const pj_char_spec spec, + pj_str_t *out); + + +/** + * Get characters from the buffer according to the spec, and return them + * in out parameter. The scanner will attempt to get as many characters as + * possible as long as the spec matches. If the first character doesn't + * match the spec, or scanner is already in EOF when this function is called, + * an exception will be thrown. + * + * @param scanner The scanner. + * @param spec The spec to match input string. + * @param out String to store the result. + */ +PJ_DECL(void) pj_scan_get( pj_scanner *scanner, + const pj_char_spec spec, pj_str_t *out); + + +/** + * Get characters between quotes. If current input doesn't match begin_quote, + * syntax error will be thrown. + * + * @param scanner The scanner. + * @param begin_quote The character to begin the quote. + * @param end_quote The character to end the quote. + * @param out String to store the result. + */ +PJ_DECL(void) pj_scan_get_quote( pj_scanner *scanner, + int begin_quote, int end_quote, + pj_str_t *out); + +/** + * Get N characters from the scanner. + * + * @param scanner The scanner. + * @param N Number of characters to get. + * @param out String to store the result. + */ +PJ_DECL(void) pj_scan_get_n( pj_scanner *scanner, + unsigned N, pj_str_t *out); + + +/** + * Get one character from the scanner. + * + * @param scanner The scanner. + * + * @return (unknown) + */ +PJ_DECL(int) pj_scan_get_char( pj_scanner *scanner ); + + +/** + * Get a newline from the scanner. A newline is defined as '\\n', or '\\r', or + * "\\r\\n". If current input is not newline, syntax error will be thrown. + * + * @param scanner The scanner. + */ +PJ_DECL(void) pj_scan_get_newline( pj_scanner *scanner ); + + +/** + * Get characters from the scanner and move the scanner position until the + * current character matches the spec. + * + * @param scanner The scanner. + * @param spec Get until the input match this spec. + * @param out String to store the result. + */ +PJ_DECL(void) pj_scan_get_until( pj_scanner *scanner, + const pj_char_spec spec, pj_str_t *out); + + +/** + * Get characters from the scanner and move the scanner position until the + * current character matches until_char. + * + * @param scanner The scanner. + * @param until_char Get until the input match this character. + * @param out String to store the result. + */ +PJ_DECL(void) pj_scan_get_until_ch( pj_scanner *scanner, + int until_char, pj_str_t *out); + + +/** + * Get characters from the scanner and move the scanner position until the + * current character matches until_char. + * + * @param scanner The scanner. + * @param until_spec Get until the input match any of these characters. + * @param out String to store the result. + */ +PJ_DECL(void) pj_scan_get_until_chr( pj_scanner *scanner, + const char *until_spec, pj_str_t *out); + +/** + * Advance the scanner N characters, and skip whitespace + * if necessary. + * + * @param scanner The scanner. + * @param N Number of characters to skip. + * @param skip Flag to specify whether whitespace should be skipped + * after skipping the characters. + */ +PJ_DECL(void) pj_scan_advance_n( pj_scanner *scanner, + unsigned N, pj_bool_t skip); + + +/** + * Compare string in current position with the specified string. + * + * @param scanner The scanner. + * @param s The string to compare with. + * @param len Length of the string to compare. + * + * @return zero, <0, or >0 (just like strcmp()). + */ +PJ_DECL(int) pj_scan_strcmp( pj_scanner *scanner, const char *s, int len); + + +/** + * Case-less string comparison of current position with the specified + * string. + * + * @param scanner The scanner. + * @param s The string to compare with. + * @param len Length of the string to compare with. + * + * @return zero, <0, or >0 (just like strcmp()). + */ +PJ_DECL(int) pj_scan_stricmp( pj_scanner *scanner, const char *s, int len); + + +/** + * Manually skip whitespaces according to flag that was specified when + * the scanner was initialized. + * + * @param scanner The scanner. + */ +PJ_DECL(void) pj_scan_skip_whitespace( pj_scanner *scanner ); + + +/** + * Save the full scanner state. + * + * @param scanner The scanner. + * @param state Variable to store scanner's state. + */ +PJ_DECL(void) pj_scan_save_state( pj_scanner *scanner, pj_scan_state *state); + + +/** + * Restore the full scanner state. + * Note that this would not restore the string if application has modified + * it. This will only restore the scanner scanning position. + * + * @param scanner The scanner. + * @param state State of the scanner. + */ +PJ_DECL(void) pj_scan_restore_state( pj_scanner *scanner, + pj_scan_state *state); + +/** + * @} + */ + +#if PJ_FUNCTIONS_ARE_INLINED +# include "scanner_i.h" +#endif + + +PJ_END_DECL + +#endif + diff --git a/pjlib/include/pj/sock.h b/pjlib/include/pj/sock.h index c0aa56c1..fee0f6a9 100644 --- a/pjlib/include/pj/sock.h +++ b/pjlib/include/pj/sock.h @@ -1,677 +1,677 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/sock.h 10 10/14/05 12:26a Bennylp $ */ - -#ifndef __PJ_SOCK_H__ -#define __PJ_SOCK_H__ - -/** - * @file sock.h - * @brief Socket Abstraction. - */ - -#include - -PJ_BEGIN_DECL - - -/** - * @defgroup PJ_SOCK Socket Abstraction - * @ingroup PJ_IO - * @{ - * - * The PJLIB socket abstraction layer is a thin and very portable abstraction - * for socket API. It provides API similar to BSD socket API. The abstraction - * is needed because BSD socket API is not always available on all platforms, - * therefore it wouldn't be possible to create a trully portable network - * programs unless we provide such abstraction. - * - * Applications can use this API directly in their application, just - * as they would when using traditional BSD socket API, provided they - * call #pj_init() first. - * - * \section pj_sock_examples_sec Examples - * - * For some examples on how to use the socket API, please see: - * - * - \ref page_pjlib_sock_test - * - \ref page_pjlib_select_test - * - \ref page_pjlib_sock_perf_test - */ - - -/** - * Supported address families. - * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL AF_*, BECAUSE - * THE LIBRARY WILL DO TRANSLATION TO THE NATIVE VALUE. - */ -extern const pj_uint16_t PJ_AF_UNIX; /**< Unix domain socket. */ -#define PJ_AF_LOCAL PJ_AF_UNIX; /**< POSIX name for AF_UNIX */ -extern const pj_uint16_t PJ_AF_INET; /**< Internet IP protocol. */ -extern const pj_uint16_t PJ_AF_INET6; /**< IP version 6. */ -extern const pj_uint16_t PJ_AF_PACKET; /**< Packet family. */ -extern const pj_uint16_t PJ_AF_IRDA; /**< IRDA sockets. */ - - -/** - * Supported types of sockets. - * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL SOCK_*, BECAUSE - * THE LIBRARY WILL TRANSLATE THE VALUE TO THE NATIVE VALUE. - */ - -extern const pj_uint16_t PJ_SOCK_STREAM; /**< Sequenced, reliable, connection- - based byte streams. */ -extern const pj_uint16_t PJ_SOCK_DGRAM; /**< Connectionless, unreliable - datagrams of fixed maximum - lengths. */ -extern const pj_uint16_t PJ_SOCK_RAW; /**< Raw protocol interface. */ -extern const pj_uint16_t PJ_SOCK_RDM; /**< Reliably-delivered messages. */ - - -/** - * Socket level specified in #pj_sock_setsockopt(). - * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL SOL_*, BECAUSE - * THE LIBRARY WILL TRANSLATE THE VALUE TO THE NATIVE VALUE. - */ -extern const pj_uint16_t PJ_SOL_SOCKET; /**< Socket level. */ -extern const pj_uint16_t PJ_SOL_IP; /**< IP level. */ -extern const pj_uint16_t PJ_SOL_TCP; /**< TCP level. */ -extern const pj_uint16_t PJ_SOL_UDP; /**< UDP level. */ -extern const pj_uint16_t PJ_SOL_IPV6; /**< IP version 6 */ - -/** - * Flags to be specified in #pj_sock_recv, #pj_sock_send, etc. - */ -typedef enum pj_sock_msg_flag -{ - PJ_MSG_OOB = 0x01, /**< Out-of-band messages. */ - PJ_MSG_PEEK = 0x02, /**< Peek, don't remove from buffer. */ - PJ_MSG_DONTROUTE = 0x04, /**< Don't route. */ -} pj_sock_msg_flag; - - -/** - * Flag to be specified in #pj_sock_shutdown. - */ -typedef enum pj_socket_sd_type -{ - PJ_SD_RECEIVE = 0, /**< No more receive. */ - PJ_SHUT_RD = 0, /**< Alias for SD_RECEIVE. */ - PJ_SD_SEND = 1, /**< No more sending. */ - PJ_SHUT_WR = 1, /**< Alias for SD_SEND. */ - PJ_SD_BOTH = 2, /**< No more send and receive. */ - PJ_SHUT_RDWR = 2, /**< Alias for SD_BOTH. */ -} pj_socket_sd_type; - - - -/** Address to accept any incoming messages. */ -#define PJ_INADDR_ANY ((pj_uint32_t)0) - -/** Address indicating an error return */ -#define PJ_INADDR_NONE ((pj_uint32_t)0xffffffff) - -/** Address to send to all hosts. */ -#define PJ_INADDR_BROADCAST ((pj_uint32_t)0xffffffff) - - -/** - * Maximum length specifiable by #pj_sock_listen(). - * If the build system doesn't override this value, then the lowest - * denominator (five, in Win32 systems) will be used. - */ -#if !defined(PJ_SOMAXCONN) -# define PJ_SOMAXCONN 5 -#endif - - -/** - * Constant for invalid socket returned by #pj_sock_socket() and - * #pj_sock_accept(). - */ -#define PJ_INVALID_SOCKET (-1) - -/** - * Structure describing a generic socket address. - */ -typedef struct pj_sockaddr -{ - pj_uint16_t sa_family; /**< Common data: address family. */ - char sa_data[14]; /**< Address data. */ -} pj_sockaddr; - - -/** - * This structure describes Internet address. - */ -typedef struct pj_in_addr -{ - pj_uint32_t s_addr; /**< The 32bit IP address. */ -} pj_in_addr; - - -/** - * This structure describes Internet socket address. - */ -typedef struct pj_sockaddr_in -{ - pj_uint16_t sin_family; /**< Address family. */ - pj_uint16_t sin_port; /**< Transport layer port number. */ - pj_in_addr sin_addr; /**< IP address. */ - char sin_zero[8]; /**< Padding. */ -} pj_sockaddr_in; - - -/** - * This structure describes IPv6 address. - */ -typedef struct pj_in6_addr -{ - /** Union of address formats. */ - union { - pj_uint8_t u6_addr8[16]; /**< u6_addr8 */ - pj_uint16_t u6_addr16[8]; /**< u6_addr16 */ - pj_uint32_t u6_addr32[4]; /**< u6_addr32 */ - } in6_u; -/** Shortcut to access in6_u.u6_addr8. */ -#define s6_addr in6_u.u6_addr8 -/** Shortcut to access in6_u.u6_addr16. */ -#define s6_addr16 in6_u.u6_addr16 -/** Shortcut to access in6_u.u6_addr32. */ -#define s6_addr32 in6_u.u6_addr32 -} pj_in6_addr; - -/** Initializer value for pj_in6_addr. */ -#define PJ_IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } - -/** Initializer value for pj_in6_addr. */ -#define PJ_IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } - -/** - * This structure describes IPv6 socket address. - */ -typedef struct pj_sockaddr_in6 -{ - pj_uint16_t sin6_family; /**< Address family */ - pj_uint16_t sin6_port; /**< Transport layer port number. */ - pj_uint32_t sin6_flowinfo; /**< IPv6 flow information */ - pj_in6_addr sin6_addr; /**< IPv6 address. */ - pj_uint32_t sin6_scope_id; /**< IPv6 scope-id */ -} pj_sockaddr_in6; - - -/***************************************************************************** - * - * SOCKET ADDRESS MANIPULATION. - * - ***************************************************************************** - */ - -/** - * Convert 16-bit value from network byte order to host byte order. - * - * @param netshort 16-bit network value. - * @return 16-bit host value. - */ -PJ_DECL(pj_uint16_t) pj_ntohs(pj_uint16_t netshort); - -/** - * Convert 16-bit value from host byte order to network byte order. - * - * @param hostshort 16-bit host value. - * @return 16-bit network value. - */ -PJ_DECL(pj_uint16_t) pj_htons(pj_uint16_t hostshort); - -/** - * Convert 32-bit value from network byte order to host byte order. - * - * @param netlong 32-bit network value. - * @return 32-bit host value. - */ -PJ_DECL(pj_uint32_t) pj_ntohl(pj_uint32_t netlong); - -/** - * Convert 32-bit value from host byte order to network byte order. - * - * @param hostlong 32-bit host value. - * @return 32-bit network value. - */ -PJ_DECL(pj_uint32_t) pj_htonl(pj_uint32_t hostlong); - -/** - * Convert an Internet host address given in network byte order - * to string in standard numbers and dots notation. - * - * @param inaddr The host address. - * @return The string address. - */ -PJ_DECL(char*) pj_inet_ntoa(pj_in_addr inaddr); - -/** - * This function converts the Internet host address cp from the standard - * numbers-and-dots notation into binary data and stores it in the structure - * that inp points to. - * - * @param cp IP address in standard numbers-and-dots notation. - * @param inp Structure that holds the output of the conversion. - * - * @return nonzero if the address is valid, zero if not. - */ -PJ_DECL(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp); - -/** - * Convert address string with numbers and dots to binary IP address. - * - * @param cp The IP address in numbers and dots notation. - * @return If success, the IP address is returned in network - * byte order. If failed, PJ_INADDR_NONE will be - * returned. - * @remark - * This is an obsolete interface to #pj_inet_aton(); it is obsolete - * because -1 is a valid address (255.255.255.255), and #pj_inet_aton() - * provides a cleaner way to indicate error return. - */ -PJ_DECL(pj_in_addr) pj_inet_addr(const pj_str_t *cp); - - -/** - * Get the transport layer port number of an Internet socket address. - * The port is returned in host byte order. - * - * @param addr The IP socket address. - * @return Port number, in host byte order. - */ -PJ_INLINE(pj_uint16_t) pj_sockaddr_in_get_port(const pj_sockaddr_in *addr) -{ - return pj_ntohs(addr->sin_port); -} - -/** - * Set the port number of an Internet socket address. - * - * @param addr The IP socket address. - * @param hostport The port number, in host byte order. - */ -PJ_INLINE(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr, - pj_uint16_t hostport) -{ - addr->sin_port = pj_htons(hostport); -} - -/** - * Get the IP address of an Internet socket address. - * The address is returned as 32bit value in host byte order. - * - * @param addr The IP socket address. - * @return 32bit address, in host byte order. - */ -PJ_INLINE(pj_in_addr) pj_sockaddr_in_get_addr(const pj_sockaddr_in *addr) -{ - pj_in_addr in_addr; - in_addr.s_addr = pj_ntohl(addr->sin_addr.s_addr); - return in_addr; -}; - -/** - * Set the IP address of an Internet socket address. - * - * @param addr The IP socket address. - * @param hostaddr The host address, in host byte order. - */ -PJ_INLINE(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr, - pj_uint32_t hostaddr) -{ - addr->sin_addr.s_addr = pj_htonl(hostaddr); -} - -/** - * Set the IP address of an IP socket address from string address, - * with resolving the host if necessary. The string address may be in a - * standard numbers and dots notation or may be a hostname. If hostname - * is specified, then the function will resolve the host into the IP - * address. - * - * @param addr The IP socket address to be set. - * @param cp The address string, which can be in a standard - * dotted numbers or a hostname to be resolved. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr, - const pj_str_t *cp); - -/** - * Set the IP address and port of an IP socket address. - * The string address may be in a standard numbers and dots notation or - * may be a hostname. If hostname is specified, then the function will - * resolve the host into the IP address. - * - * @param addr The IP socket address to be set. - * @param cp The address string, which can be in a standard - * dotted numbers or a hostname to be resolved. - * @param port The port number, in host byte order. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr, - const pj_str_t *cp, - pj_uint16_t port); - - -/***************************************************************************** - * - * HOST NAME AND ADDRESS. - * - ***************************************************************************** - */ - -/** - * Get system's host name. - * - * @return The hostname, or empty string if the hostname can not - * be identified. - */ -PJ_DECL(const pj_str_t*) pj_gethostname(void); - -/** - * Get host's IP address, which the the first IP address that is resolved - * from the hostname. - * - * @return The host's IP address, PJ_INADDR_NONE if the host - * IP address can not be identified. - */ -PJ_DECL(pj_in_addr) pj_gethostaddr(void); - - -/***************************************************************************** - * - * SOCKET API. - * - ***************************************************************************** - */ - -/** - * Create new socket/endpoint for communication. - * - * @param family Specifies a communication domain; this selects the - * protocol family which will be used for communication. - * @param type The socket has the indicated type, which specifies the - * communication semantics. - * @param protocol Specifies a particular protocol to be used with the - * socket. Normally only a single protocol exists to support - * a particular socket type within a given protocol family, - * in which a case protocol can be specified as 0. - * @param sock New socket descriptor, or PJ_INVALID_SOCKET on error. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_socket(int family, - int type, - int protocol, - pj_sock_t *sock); - -/** - * Close the socket descriptor. - * - * @param sockfd The socket descriptor. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_close(pj_sock_t sockfd); - - -/** - * This function gives the socket sockfd the local address my_addr. my_addr is - * addrlen bytes long. Traditionally, this is called assigning a name to - * a socket. When a socket is created with #pj_sock_socket(), it exists in a - * name space (address family) but has no name assigned. - * - * @param sockfd The socket desriptor. - * @param my_addr The local address to bind the socket to. - * @param addrlen The length of the address. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_bind( pj_sock_t sockfd, - const pj_sockaddr_t *my_addr, - int addrlen); - -/** - * Bind the IP socket sockfd to the given address and port. - * - * @param sockfd The socket descriptor. - * @param addr Local address to bind the socket to, in host byte order. - * @param port The local port to bind the socket to, in host byte order. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_bind_in( pj_sock_t sockfd, - pj_uint32_t addr, - pj_uint16_t port); - -#if PJ_HAS_TCP -/** - * Listen for incoming connection. This function only applies to connection - * oriented sockets (such as PJ_SOCK_STREAM or PJ_SOCK_SEQPACKET), and it - * indicates the willingness to accept incoming connections. - * - * @param sockfd The socket descriptor. - * @param backlog Defines the maximum length the queue of pending - * connections may grow to. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_listen( pj_sock_t sockfd, - int backlog ); - -/** - * Accept new connection on the specified connection oriented server socket. - * - * @param serverfd The server socket. - * @param newsock New socket on success, of PJ_INVALID_SOCKET if failed. - * @param addr A pointer to sockaddr type. If the argument is not NULL, - * it will be filled by the address of connecting entity. - * @param addrlen Initially specifies the length of the address, and upon - * return will be filled with the exact address length. - * - * @return Zero on success, or the error number. - */ -PJ_DECL(pj_status_t) pj_sock_accept( pj_sock_t serverfd, - pj_sock_t *newsock, - pj_sockaddr_t *addr, - int *addrlen); -#endif - -/** - * The file descriptor sockfd must refer to a socket. If the socket is of - * type PJ_SOCK_DGRAM then the serv_addr address is the address to which - * datagrams are sent by default, and the only address from which datagrams - * are received. If the socket is of type PJ_SOCK_STREAM or PJ_SOCK_SEQPACKET, - * this call attempts to make a connection to another socket. The - * other socket is specified by serv_addr, which is an address (of length - * addrlen) in the communications space of the socket. Each communications - * space interprets the serv_addr parameter in its own way. - * - * @param sockfd The socket descriptor. - * @param serv_addr Server address to connect to. - * @param addrlen The length of server address. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_connect( pj_sock_t sockfd, - const pj_sockaddr_t *serv_addr, - int addrlen); - -/** - * Return the address of peer which is connected to socket sockfd. - * - * @param sockfd The socket descriptor. - * @param addr Pointer to sockaddr structure to which the address - * will be returned. - * @param namelen Initially the length of the addr. Upon return the value - * will be set to the actual length of the address. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_getpeername(pj_sock_t sockfd, - pj_sockaddr_t *addr, - int *namelen); - -/** - * Return the current name of the specified socket. - * - * @param sockfd The socket descriptor. - * @param addr Pointer to sockaddr structure to which the address - * will be returned. - * @param namelen Initially the length of the addr. Upon return the value - * will be set to the actual length of the address. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_getsockname( pj_sock_t sockfd, - pj_sockaddr_t *addr, - int *namelen); - -/** - * Get socket option associated with a socket. Options may exist at multiple - * protocol levels; they are always present at the uppermost socket level. - * - * @param sockfd The socket descriptor. - * @param level The level which to get the option from. - * @param optname The option name, which will be passed uninterpreted - * by the library. - * @param optval Identifies the buffer which the value will be - * returned. - * @param optlen Initially contains the length of the buffer, upon - * return will be set to the actual size of the value. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_getsockopt( pj_sock_t sockfd, - int level, - int optname, - void *optval, - int *optlen); -/** - * Manipulate the options associated with a socket. Options may exist at - * multiple protocol levels; they are always present at the uppermost socket - * level. - * - * @param sockfd The socket descriptor. - * @param level The level which to get the option from. - * @param optname The option name, which will be passed uninterpreted - * by the library. - * @param optval Identifies the buffer which contain the value. - * @param optlen The length of the value. - * - * @return PJ_SUCCESS or the status code. - */ -PJ_DECL(pj_status_t) pj_sock_setsockopt( pj_sock_t sockfd, - int level, - int optname, - const void *optval, - int optlen); - - -/** - * Receives data stream or message coming to the specified socket. - * - * @param sockfd The socket descriptor. - * @param buf The buffer to receive the data or message. - * @param len On input, the length of the buffer. On return, - * contains the length of data received. - * @param flags Combination of #pj_sock_msg_flag. - * - * @return PJ_SUCCESS or the error code. - */ -PJ_DECL(pj_status_t) pj_sock_recv(pj_sock_t sockfd, - void *buf, - pj_ssize_t *len, - unsigned flags); - -/** - * Receives data stream or message coming to the specified socket. - * - * @param sockfd The socket descriptor. - * @param buf The buffer to receive the data or message. - * @param len On input, the length of the buffer. On return, - * contains the length of data received. - * @param flags Bitmask combination of #pj_sock_msg_flag. - * @param from If not NULL, it will be filled with the source - * address of the connection. - * @param fromlen Initially contains the length of from address, - * and upon return will be filled with the actual - * length of the address. - * - * @return PJ_SUCCESS or the error code. - */ -PJ_DECL(pj_status_t) pj_sock_recvfrom( pj_sock_t sockfd, - void *buf, - pj_ssize_t *len, - unsigned flags, - pj_sockaddr_t *from, - int *fromlen); - -/** - * Transmit data to the socket. - * - * @param sockfd Socket descriptor. - * @param buf Buffer containing data to be sent. - * @param len On input, the length of the data in the buffer. - * Upon return, it will be filled with the length - * of data sent. - * @param flags Bitmask combination of #pj_sock_msg_flag. - * - * @return PJ_SUCCESS or the status code. - */ -PJ_DECL(pj_status_t) pj_sock_send(pj_sock_t sockfd, - const void *buf, - pj_ssize_t *len, - unsigned flags); - -/** - * Transmit data to the socket to the specified address. - * - * @param sockfd Socket descriptor. - * @param buf Buffer containing data to be sent. - * @param len On input, the length of the data in the buffer. - * Upon return, it will be filled with the length - * of data sent. - * @param flags Bitmask combination of #pj_sock_msg_flag. - * @param to The address to send. - * @param tolen The length of the address in bytes. - * - * @return The length of data successfully sent. - */ -PJ_DECL(pj_status_t) pj_sock_sendto(pj_sock_t sockfd, - const void *buf, - pj_ssize_t *len, - unsigned flags, - const pj_sockaddr_t *to, - int tolen); - -#if PJ_HAS_TCP -/** - * The shutdown call causes all or part of a full-duplex connection on the - * socket associated with sockfd to be shut down. - * - * @param sockfd The socket descriptor. - * @param how If how is PJ_SHUT_RD, further receptions will be - * disallowed. If how is PJ_SHUT_WR, further transmissions - * will be disallowed. If how is PJ_SHUT_RDWR, further - * receptions andtransmissions will be disallowed. - * - * @return Zero on success. - */ -PJ_DECL(pj_status_t) pj_sock_shutdown( pj_sock_t sockfd, - int how); -#endif - -/** - * @} - */ - - -PJ_END_DECL - -#endif /* __PJ_SOCK_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/sock.h 10 10/14/05 12:26a Bennylp $ */ + +#ifndef __PJ_SOCK_H__ +#define __PJ_SOCK_H__ + +/** + * @file sock.h + * @brief Socket Abstraction. + */ + +#include + +PJ_BEGIN_DECL + + +/** + * @defgroup PJ_SOCK Socket Abstraction + * @ingroup PJ_IO + * @{ + * + * The PJLIB socket abstraction layer is a thin and very portable abstraction + * for socket API. It provides API similar to BSD socket API. The abstraction + * is needed because BSD socket API is not always available on all platforms, + * therefore it wouldn't be possible to create a trully portable network + * programs unless we provide such abstraction. + * + * Applications can use this API directly in their application, just + * as they would when using traditional BSD socket API, provided they + * call #pj_init() first. + * + * \section pj_sock_examples_sec Examples + * + * For some examples on how to use the socket API, please see: + * + * - \ref page_pjlib_sock_test + * - \ref page_pjlib_select_test + * - \ref page_pjlib_sock_perf_test + */ + + +/** + * Supported address families. + * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL AF_*, BECAUSE + * THE LIBRARY WILL DO TRANSLATION TO THE NATIVE VALUE. + */ +extern const pj_uint16_t PJ_AF_UNIX; /**< Unix domain socket. */ +#define PJ_AF_LOCAL PJ_AF_UNIX; /**< POSIX name for AF_UNIX */ +extern const pj_uint16_t PJ_AF_INET; /**< Internet IP protocol. */ +extern const pj_uint16_t PJ_AF_INET6; /**< IP version 6. */ +extern const pj_uint16_t PJ_AF_PACKET; /**< Packet family. */ +extern const pj_uint16_t PJ_AF_IRDA; /**< IRDA sockets. */ + + +/** + * Supported types of sockets. + * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL SOCK_*, BECAUSE + * THE LIBRARY WILL TRANSLATE THE VALUE TO THE NATIVE VALUE. + */ + +extern const pj_uint16_t PJ_SOCK_STREAM; /**< Sequenced, reliable, connection- + based byte streams. */ +extern const pj_uint16_t PJ_SOCK_DGRAM; /**< Connectionless, unreliable + datagrams of fixed maximum + lengths. */ +extern const pj_uint16_t PJ_SOCK_RAW; /**< Raw protocol interface. */ +extern const pj_uint16_t PJ_SOCK_RDM; /**< Reliably-delivered messages. */ + + +/** + * Socket level specified in #pj_sock_setsockopt(). + * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL SOL_*, BECAUSE + * THE LIBRARY WILL TRANSLATE THE VALUE TO THE NATIVE VALUE. + */ +extern const pj_uint16_t PJ_SOL_SOCKET; /**< Socket level. */ +extern const pj_uint16_t PJ_SOL_IP; /**< IP level. */ +extern const pj_uint16_t PJ_SOL_TCP; /**< TCP level. */ +extern const pj_uint16_t PJ_SOL_UDP; /**< UDP level. */ +extern const pj_uint16_t PJ_SOL_IPV6; /**< IP version 6 */ + +/** + * Flags to be specified in #pj_sock_recv, #pj_sock_send, etc. + */ +typedef enum pj_sock_msg_flag +{ + PJ_MSG_OOB = 0x01, /**< Out-of-band messages. */ + PJ_MSG_PEEK = 0x02, /**< Peek, don't remove from buffer. */ + PJ_MSG_DONTROUTE = 0x04, /**< Don't route. */ +} pj_sock_msg_flag; + + +/** + * Flag to be specified in #pj_sock_shutdown. + */ +typedef enum pj_socket_sd_type +{ + PJ_SD_RECEIVE = 0, /**< No more receive. */ + PJ_SHUT_RD = 0, /**< Alias for SD_RECEIVE. */ + PJ_SD_SEND = 1, /**< No more sending. */ + PJ_SHUT_WR = 1, /**< Alias for SD_SEND. */ + PJ_SD_BOTH = 2, /**< No more send and receive. */ + PJ_SHUT_RDWR = 2, /**< Alias for SD_BOTH. */ +} pj_socket_sd_type; + + + +/** Address to accept any incoming messages. */ +#define PJ_INADDR_ANY ((pj_uint32_t)0) + +/** Address indicating an error return */ +#define PJ_INADDR_NONE ((pj_uint32_t)0xffffffff) + +/** Address to send to all hosts. */ +#define PJ_INADDR_BROADCAST ((pj_uint32_t)0xffffffff) + + +/** + * Maximum length specifiable by #pj_sock_listen(). + * If the build system doesn't override this value, then the lowest + * denominator (five, in Win32 systems) will be used. + */ +#if !defined(PJ_SOMAXCONN) +# define PJ_SOMAXCONN 5 +#endif + + +/** + * Constant for invalid socket returned by #pj_sock_socket() and + * #pj_sock_accept(). + */ +#define PJ_INVALID_SOCKET (-1) + +/** + * Structure describing a generic socket address. + */ +typedef struct pj_sockaddr +{ + pj_uint16_t sa_family; /**< Common data: address family. */ + char sa_data[14]; /**< Address data. */ +} pj_sockaddr; + + +/** + * This structure describes Internet address. + */ +typedef struct pj_in_addr +{ + pj_uint32_t s_addr; /**< The 32bit IP address. */ +} pj_in_addr; + + +/** + * This structure describes Internet socket address. + */ +typedef struct pj_sockaddr_in +{ + pj_uint16_t sin_family; /**< Address family. */ + pj_uint16_t sin_port; /**< Transport layer port number. */ + pj_in_addr sin_addr; /**< IP address. */ + char sin_zero[8]; /**< Padding. */ +} pj_sockaddr_in; + + +/** + * This structure describes IPv6 address. + */ +typedef struct pj_in6_addr +{ + /** Union of address formats. */ + union { + pj_uint8_t u6_addr8[16]; /**< u6_addr8 */ + pj_uint16_t u6_addr16[8]; /**< u6_addr16 */ + pj_uint32_t u6_addr32[4]; /**< u6_addr32 */ + } in6_u; +/** Shortcut to access in6_u.u6_addr8. */ +#define s6_addr in6_u.u6_addr8 +/** Shortcut to access in6_u.u6_addr16. */ +#define s6_addr16 in6_u.u6_addr16 +/** Shortcut to access in6_u.u6_addr32. */ +#define s6_addr32 in6_u.u6_addr32 +} pj_in6_addr; + +/** Initializer value for pj_in6_addr. */ +#define PJ_IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } + +/** Initializer value for pj_in6_addr. */ +#define PJ_IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } + +/** + * This structure describes IPv6 socket address. + */ +typedef struct pj_sockaddr_in6 +{ + pj_uint16_t sin6_family; /**< Address family */ + pj_uint16_t sin6_port; /**< Transport layer port number. */ + pj_uint32_t sin6_flowinfo; /**< IPv6 flow information */ + pj_in6_addr sin6_addr; /**< IPv6 address. */ + pj_uint32_t sin6_scope_id; /**< IPv6 scope-id */ +} pj_sockaddr_in6; + + +/***************************************************************************** + * + * SOCKET ADDRESS MANIPULATION. + * + ***************************************************************************** + */ + +/** + * Convert 16-bit value from network byte order to host byte order. + * + * @param netshort 16-bit network value. + * @return 16-bit host value. + */ +PJ_DECL(pj_uint16_t) pj_ntohs(pj_uint16_t netshort); + +/** + * Convert 16-bit value from host byte order to network byte order. + * + * @param hostshort 16-bit host value. + * @return 16-bit network value. + */ +PJ_DECL(pj_uint16_t) pj_htons(pj_uint16_t hostshort); + +/** + * Convert 32-bit value from network byte order to host byte order. + * + * @param netlong 32-bit network value. + * @return 32-bit host value. + */ +PJ_DECL(pj_uint32_t) pj_ntohl(pj_uint32_t netlong); + +/** + * Convert 32-bit value from host byte order to network byte order. + * + * @param hostlong 32-bit host value. + * @return 32-bit network value. + */ +PJ_DECL(pj_uint32_t) pj_htonl(pj_uint32_t hostlong); + +/** + * Convert an Internet host address given in network byte order + * to string in standard numbers and dots notation. + * + * @param inaddr The host address. + * @return The string address. + */ +PJ_DECL(char*) pj_inet_ntoa(pj_in_addr inaddr); + +/** + * This function converts the Internet host address cp from the standard + * numbers-and-dots notation into binary data and stores it in the structure + * that inp points to. + * + * @param cp IP address in standard numbers-and-dots notation. + * @param inp Structure that holds the output of the conversion. + * + * @return nonzero if the address is valid, zero if not. + */ +PJ_DECL(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp); + +/** + * Convert address string with numbers and dots to binary IP address. + * + * @param cp The IP address in numbers and dots notation. + * @return If success, the IP address is returned in network + * byte order. If failed, PJ_INADDR_NONE will be + * returned. + * @remark + * This is an obsolete interface to #pj_inet_aton(); it is obsolete + * because -1 is a valid address (255.255.255.255), and #pj_inet_aton() + * provides a cleaner way to indicate error return. + */ +PJ_DECL(pj_in_addr) pj_inet_addr(const pj_str_t *cp); + + +/** + * Get the transport layer port number of an Internet socket address. + * The port is returned in host byte order. + * + * @param addr The IP socket address. + * @return Port number, in host byte order. + */ +PJ_INLINE(pj_uint16_t) pj_sockaddr_in_get_port(const pj_sockaddr_in *addr) +{ + return pj_ntohs(addr->sin_port); +} + +/** + * Set the port number of an Internet socket address. + * + * @param addr The IP socket address. + * @param hostport The port number, in host byte order. + */ +PJ_INLINE(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr, + pj_uint16_t hostport) +{ + addr->sin_port = pj_htons(hostport); +} + +/** + * Get the IP address of an Internet socket address. + * The address is returned as 32bit value in host byte order. + * + * @param addr The IP socket address. + * @return 32bit address, in host byte order. + */ +PJ_INLINE(pj_in_addr) pj_sockaddr_in_get_addr(const pj_sockaddr_in *addr) +{ + pj_in_addr in_addr; + in_addr.s_addr = pj_ntohl(addr->sin_addr.s_addr); + return in_addr; +}; + +/** + * Set the IP address of an Internet socket address. + * + * @param addr The IP socket address. + * @param hostaddr The host address, in host byte order. + */ +PJ_INLINE(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr, + pj_uint32_t hostaddr) +{ + addr->sin_addr.s_addr = pj_htonl(hostaddr); +} + +/** + * Set the IP address of an IP socket address from string address, + * with resolving the host if necessary. The string address may be in a + * standard numbers and dots notation or may be a hostname. If hostname + * is specified, then the function will resolve the host into the IP + * address. + * + * @param addr The IP socket address to be set. + * @param cp The address string, which can be in a standard + * dotted numbers or a hostname to be resolved. + * + * @return Zero on success. + */ +PJ_DECL(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr, + const pj_str_t *cp); + +/** + * Set the IP address and port of an IP socket address. + * The string address may be in a standard numbers and dots notation or + * may be a hostname. If hostname is specified, then the function will + * resolve the host into the IP address. + * + * @param addr The IP socket address to be set. + * @param cp The address string, which can be in a standard + * dotted numbers or a hostname to be resolved. + * @param port The port number, in host byte order. + * + * @return Zero on success. + */ +PJ_DECL(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr, + const pj_str_t *cp, + pj_uint16_t port); + + +/***************************************************************************** + * + * HOST NAME AND ADDRESS. + * + ***************************************************************************** + */ + +/** + * Get system's host name. + * + * @return The hostname, or empty string if the hostname can not + * be identified. + */ +PJ_DECL(const pj_str_t*) pj_gethostname(void); + +/** + * Get host's IP address, which the the first IP address that is resolved + * from the hostname. + * + * @return The host's IP address, PJ_INADDR_NONE if the host + * IP address can not be identified. + */ +PJ_DECL(pj_in_addr) pj_gethostaddr(void); + + +/***************************************************************************** + * + * SOCKET API. + * + ***************************************************************************** + */ + +/** + * Create new socket/endpoint for communication. + * + * @param family Specifies a communication domain; this selects the + * protocol family which will be used for communication. + * @param type The socket has the indicated type, which specifies the + * communication semantics. + * @param protocol Specifies a particular protocol to be used with the + * socket. Normally only a single protocol exists to support + * a particular socket type within a given protocol family, + * in which a case protocol can be specified as 0. + * @param sock New socket descriptor, or PJ_INVALID_SOCKET on error. + * + * @return Zero on success. + */ +PJ_DECL(pj_status_t) pj_sock_socket(int family, + int type, + int protocol, + pj_sock_t *sock); + +/** + * Close the socket descriptor. + * + * @param sockfd The socket descriptor. + * + * @return Zero on success. + */ +PJ_DECL(pj_status_t) pj_sock_close(pj_sock_t sockfd); + + +/** + * This function gives the socket sockfd the local address my_addr. my_addr is + * addrlen bytes long. Traditionally, this is called assigning a name to + * a socket. When a socket is created with #pj_sock_socket(), it exists in a + * name space (address family) but has no name assigned. + * + * @param sockfd The socket desriptor. + * @param my_addr The local address to bind the socket to. + * @param addrlen The length of the address. + * + * @return Zero on success. + */ +PJ_DECL(pj_status_t) pj_sock_bind( pj_sock_t sockfd, + const pj_sockaddr_t *my_addr, + int addrlen); + +/** + * Bind the IP socket sockfd to the given address and port. + * + * @param sockfd The socket descriptor. + * @param addr Local address to bind the socket to, in host byte order. + * @param port The local port to bind the socket to, in host byte order. + * + * @return Zero on success. + */ +PJ_DECL(pj_status_t) pj_sock_bind_in( pj_sock_t sockfd, + pj_uint32_t addr, + pj_uint16_t port); + +#if PJ_HAS_TCP +/** + * Listen for incoming connection. This function only applies to connection + * oriented sockets (such as PJ_SOCK_STREAM or PJ_SOCK_SEQPACKET), and it + * indicates the willingness to accept incoming connections. + * + * @param sockfd The socket descriptor. + * @param backlog Defines the maximum length the queue of pending + * connections may grow to. + * + * @return Zero on success. + */ +PJ_DECL(pj_status_t) pj_sock_listen( pj_sock_t sockfd, + int backlog ); + +/** + * Accept new connection on the specified connection oriented server socket. + * + * @param serverfd The server socket. + * @param newsock New socket on success, of PJ_INVALID_SOCKET if failed. + * @param addr A pointer to sockaddr type. If the argument is not NULL, + * it will be filled by the address of connecting entity. + * @param addrlen Initially specifies the length of the address, and upon + * return will be filled with the exact address length. + * + * @return Zero on success, or the error number. + */ +PJ_DECL(pj_status_t) pj_sock_accept( pj_sock_t serverfd, + pj_sock_t *newsock, + pj_sockaddr_t *addr, + int *addrlen); +#endif + +/** + * The file descriptor sockfd must refer to a socket. If the socket is of + * type PJ_SOCK_DGRAM then the serv_addr address is the address to which + * datagrams are sent by default, and the only address from which datagrams + * are received. If the socket is of type PJ_SOCK_STREAM or PJ_SOCK_SEQPACKET, + * this call attempts to make a connection to another socket. The + * other socket is specified by serv_addr, which is an address (of length + * addrlen) in the communications space of the socket. Each communications + * space interprets the serv_addr parameter in its own way. + * + * @param sockfd The socket descriptor. + * @param serv_addr Server address to connect to. + * @param addrlen The length of server address. + * + * @return Zero on success. + */ +PJ_DECL(pj_status_t) pj_sock_connect( pj_sock_t sockfd, + const pj_sockaddr_t *serv_addr, + int addrlen); + +/** + * Return the address of peer which is connected to socket sockfd. + * + * @param sockfd The socket descriptor. + * @param addr Pointer to sockaddr structure to which the address + * will be returned. + * @param namelen Initially the length of the addr. Upon return the value + * will be set to the actual length of the address. + * + * @return Zero on success. + */ +PJ_DECL(pj_status_t) pj_sock_getpeername(pj_sock_t sockfd, + pj_sockaddr_t *addr, + int *namelen); + +/** + * Return the current name of the specified socket. + * + * @param sockfd The socket descriptor. + * @param addr Pointer to sockaddr structure to which the address + * will be returned. + * @param namelen Initially the length of the addr. Upon return the value + * will be set to the actual length of the address. + * + * @return Zero on success. + */ +PJ_DECL(pj_status_t) pj_sock_getsockname( pj_sock_t sockfd, + pj_sockaddr_t *addr, + int *namelen); + +/** + * Get socket option associated with a socket. Options may exist at multiple + * protocol levels; they are always present at the uppermost socket level. + * + * @param sockfd The socket descriptor. + * @param level The level which to get the option from. + * @param optname The option name, which will be passed uninterpreted + * by the library. + * @param optval Identifies the buffer which the value will be + * returned. + * @param optlen Initially contains the length of the buffer, upon + * return will be set to the actual size of the value. + * + * @return Zero on success. + */ +PJ_DECL(pj_status_t) pj_sock_getsockopt( pj_sock_t sockfd, + int level, + int optname, + void *optval, + int *optlen); +/** + * Manipulate the options associated with a socket. Options may exist at + * multiple protocol levels; they are always present at the uppermost socket + * level. + * + * @param sockfd The socket descriptor. + * @param level The level which to get the option from. + * @param optname The option name, which will be passed uninterpreted + * by the library. + * @param optval Identifies the buffer which contain the value. + * @param optlen The length of the value. + * + * @return PJ_SUCCESS or the status code. + */ +PJ_DECL(pj_status_t) pj_sock_setsockopt( pj_sock_t sockfd, + int level, + int optname, + const void *optval, + int optlen); + + +/** + * Receives data stream or message coming to the specified socket. + * + * @param sockfd The socket descriptor. + * @param buf The buffer to receive the data or message. + * @param len On input, the length of the buffer. On return, + * contains the length of data received. + * @param flags Combination of #pj_sock_msg_flag. + * + * @return PJ_SUCCESS or the error code. + */ +PJ_DECL(pj_status_t) pj_sock_recv(pj_sock_t sockfd, + void *buf, + pj_ssize_t *len, + unsigned flags); + +/** + * Receives data stream or message coming to the specified socket. + * + * @param sockfd The socket descriptor. + * @param buf The buffer to receive the data or message. + * @param len On input, the length of the buffer. On return, + * contains the length of data received. + * @param flags Bitmask combination of #pj_sock_msg_flag. + * @param from If not NULL, it will be filled with the source + * address of the connection. + * @param fromlen Initially contains the length of from address, + * and upon return will be filled with the actual + * length of the address. + * + * @return PJ_SUCCESS or the error code. + */ +PJ_DECL(pj_status_t) pj_sock_recvfrom( pj_sock_t sockfd, + void *buf, + pj_ssize_t *len, + unsigned flags, + pj_sockaddr_t *from, + int *fromlen); + +/** + * Transmit data to the socket. + * + * @param sockfd Socket descriptor. + * @param buf Buffer containing data to be sent. + * @param len On input, the length of the data in the buffer. + * Upon return, it will be filled with the length + * of data sent. + * @param flags Bitmask combination of #pj_sock_msg_flag. + * + * @return PJ_SUCCESS or the status code. + */ +PJ_DECL(pj_status_t) pj_sock_send(pj_sock_t sockfd, + const void *buf, + pj_ssize_t *len, + unsigned flags); + +/** + * Transmit data to the socket to the specified address. + * + * @param sockfd Socket descriptor. + * @param buf Buffer containing data to be sent. + * @param len On input, the length of the data in the buffer. + * Upon return, it will be filled with the length + * of data sent. + * @param flags Bitmask combination of #pj_sock_msg_flag. + * @param to The address to send. + * @param tolen The length of the address in bytes. + * + * @return The length of data successfully sent. + */ +PJ_DECL(pj_status_t) pj_sock_sendto(pj_sock_t sockfd, + const void *buf, + pj_ssize_t *len, + unsigned flags, + const pj_sockaddr_t *to, + int tolen); + +#if PJ_HAS_TCP +/** + * The shutdown call causes all or part of a full-duplex connection on the + * socket associated with sockfd to be shut down. + * + * @param sockfd The socket descriptor. + * @param how If how is PJ_SHUT_RD, further receptions will be + * disallowed. If how is PJ_SHUT_WR, further transmissions + * will be disallowed. If how is PJ_SHUT_RDWR, further + * receptions andtransmissions will be disallowed. + * + * @return Zero on success. + */ +PJ_DECL(pj_status_t) pj_sock_shutdown( pj_sock_t sockfd, + int how); +#endif + +/** + * @} + */ + + +PJ_END_DECL + +#endif /* __PJ_SOCK_H__ */ + diff --git a/pjlib/include/pj/sock_select.h b/pjlib/include/pj/sock_select.h index c54b31ce..47f84082 100644 --- a/pjlib/include/pj/sock_select.h +++ b/pjlib/include/pj/sock_select.h @@ -1,141 +1,141 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/sock_select.h 3 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/include/pj/sock_select.h $ - * - * 3 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 2 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 1 9/15/05 8:40p Bennylp - * Created. - */ -#ifndef __PJ_SELECT_H__ -#define __PJ_SELECT_H__ - -/** - * @file sock_select.h - * @brief Socket select(). - */ - -#include - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_SOCK_SELECT Socket select() API. - * @ingroup PJ_IO - * @{ - * This module provides portable abstraction for \a select() like API. - * The abstraction is needed so that it can utilize various event - * dispatching mechanisms that are available across platforms. - * - * The API is very similar to normal \a select() usage. - * - * \section pj_sock_select_examples_sec Examples - * - * For some examples on how to use the select API, please see: - * - * - \ref page_pjlib_select_test - */ - -/** - * Portable structure declarations for pj_fd_set. - * The implementation of pj_sock_select() does not use this structure - * per-se, but instead it will use the native fd_set structure. However, - * we must make sure that the size of pj_fd_set_t can accomodate the - * native fd_set structure. - */ -typedef struct pj_fd_set_t -{ - pj_sock_t data[FD_SETSIZE + 4]; /**< Opaque buffer for fd_set */ -} pj_fd_set_t; - - -/** - * Initialize the descriptor set pointed to by fdsetp to the null set. - * - * @param fdsetp The descriptor set. - */ -PJ_DECL(void) PJ_FD_ZERO(pj_fd_set_t *fdsetp); - - -/** - * Add the file descriptor fd to the set pointed to by fdsetp. - * If the file descriptor fd is already in this set, there shall be no effect - * on the set, nor will an error be returned. - * - * @param fd The socket descriptor. - * @param fdsetp The descriptor set. - */ -PJ_DECL(void) PJ_FD_SET(pj_sock_t fd, pj_fd_set_t *fdsetp); - -/** - * Remove the file descriptor fd from the set pointed to by fdsetp. - * If fd is not a member of this set, there shall be no effect on the set, - * nor will an error be returned. - * - * @param fd The socket descriptor. - * @param fdsetp The descriptor set. - */ -PJ_DECL(void) PJ_FD_CLR(pj_sock_t fd, pj_fd_set_t *fdsetp); - - -/** - * Evaluate to non-zero if the file descriptor fd is a member of the set - * pointed to by fdsetp, and shall evaluate to zero otherwise. - * - * @param fd The socket descriptor. - * @param fdsetp The descriptor set. - * - * @return Nonzero if fd is member of the descriptor set. - */ -PJ_DECL(pj_bool_t) PJ_FD_ISSET(pj_sock_t fd, const pj_fd_set_t *fdsetp); - - -/** - * Get the number of descriptors in the set. - * - * @param fdsetp The descriptor set. - * - * @return Number of descriptors in the set. - */ -PJ_DECL(pj_size_t) PJ_FD_COUNT(const pj_fd_set_t *fdsetp); - - -/** - * This function wait for a number of file descriptors to change status. - * The behaviour is the same as select() function call which appear in - * standard BSD socket libraries. - * - * @param n On Unices, this specifies the highest-numbered - * descriptor in any of the three set, plus 1. On Windows, - * the value is ignored. - * @param readfds Optional pointer to a set of sockets to be checked for - * readability. - * @param writefds Optional pointer to a set of sockets to be checked for - * writability. - * @param exceptfds Optional pointer to a set of sockets to be checked for - * errors. - * @param timeout Maximum time for select to wait, or null for blocking - * operations. - * - * @return The total number of socket handles that are ready, or - * zero if the time limit expired, or -1 if an error occurred. - */ -PJ_DECL(int) pj_sock_select( int n, - pj_fd_set_t *readfds, - pj_fd_set_t *writefds, - pj_fd_set_t *exceptfds, - const pj_time_val *timeout); - - -/** - * @} - */ - - -PJ_END_DECL - -#endif /* __PJ_SELECT_H__ */ +/* $Header: /pjproject-0.3/pjlib/include/pj/sock_select.h 3 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/include/pj/sock_select.h $ + * + * 3 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 2 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 1 9/15/05 8:40p Bennylp + * Created. + */ +#ifndef __PJ_SELECT_H__ +#define __PJ_SELECT_H__ + +/** + * @file sock_select.h + * @brief Socket select(). + */ + +#include + +PJ_BEGIN_DECL + +/** + * @defgroup PJ_SOCK_SELECT Socket select() API. + * @ingroup PJ_IO + * @{ + * This module provides portable abstraction for \a select() like API. + * The abstraction is needed so that it can utilize various event + * dispatching mechanisms that are available across platforms. + * + * The API is very similar to normal \a select() usage. + * + * \section pj_sock_select_examples_sec Examples + * + * For some examples on how to use the select API, please see: + * + * - \ref page_pjlib_select_test + */ + +/** + * Portable structure declarations for pj_fd_set. + * The implementation of pj_sock_select() does not use this structure + * per-se, but instead it will use the native fd_set structure. However, + * we must make sure that the size of pj_fd_set_t can accomodate the + * native fd_set structure. + */ +typedef struct pj_fd_set_t +{ + pj_sock_t data[FD_SETSIZE + 4]; /**< Opaque buffer for fd_set */ +} pj_fd_set_t; + + +/** + * Initialize the descriptor set pointed to by fdsetp to the null set. + * + * @param fdsetp The descriptor set. + */ +PJ_DECL(void) PJ_FD_ZERO(pj_fd_set_t *fdsetp); + + +/** + * Add the file descriptor fd to the set pointed to by fdsetp. + * If the file descriptor fd is already in this set, there shall be no effect + * on the set, nor will an error be returned. + * + * @param fd The socket descriptor. + * @param fdsetp The descriptor set. + */ +PJ_DECL(void) PJ_FD_SET(pj_sock_t fd, pj_fd_set_t *fdsetp); + +/** + * Remove the file descriptor fd from the set pointed to by fdsetp. + * If fd is not a member of this set, there shall be no effect on the set, + * nor will an error be returned. + * + * @param fd The socket descriptor. + * @param fdsetp The descriptor set. + */ +PJ_DECL(void) PJ_FD_CLR(pj_sock_t fd, pj_fd_set_t *fdsetp); + + +/** + * Evaluate to non-zero if the file descriptor fd is a member of the set + * pointed to by fdsetp, and shall evaluate to zero otherwise. + * + * @param fd The socket descriptor. + * @param fdsetp The descriptor set. + * + * @return Nonzero if fd is member of the descriptor set. + */ +PJ_DECL(pj_bool_t) PJ_FD_ISSET(pj_sock_t fd, const pj_fd_set_t *fdsetp); + + +/** + * Get the number of descriptors in the set. + * + * @param fdsetp The descriptor set. + * + * @return Number of descriptors in the set. + */ +PJ_DECL(pj_size_t) PJ_FD_COUNT(const pj_fd_set_t *fdsetp); + + +/** + * This function wait for a number of file descriptors to change status. + * The behaviour is the same as select() function call which appear in + * standard BSD socket libraries. + * + * @param n On Unices, this specifies the highest-numbered + * descriptor in any of the three set, plus 1. On Windows, + * the value is ignored. + * @param readfds Optional pointer to a set of sockets to be checked for + * readability. + * @param writefds Optional pointer to a set of sockets to be checked for + * writability. + * @param exceptfds Optional pointer to a set of sockets to be checked for + * errors. + * @param timeout Maximum time for select to wait, or null for blocking + * operations. + * + * @return The total number of socket handles that are ready, or + * zero if the time limit expired, or -1 if an error occurred. + */ +PJ_DECL(int) pj_sock_select( int n, + pj_fd_set_t *readfds, + pj_fd_set_t *writefds, + pj_fd_set_t *exceptfds, + const pj_time_val *timeout); + + +/** + * @} + */ + + +PJ_END_DECL + +#endif /* __PJ_SELECT_H__ */ diff --git a/pjlib/include/pj/string.h b/pjlib/include/pj/string.h index 4562addd..c75bf2d2 100644 --- a/pjlib/include/pj/string.h +++ b/pjlib/include/pj/string.h @@ -1,515 +1,515 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/string.h 8 10/14/05 12:26a Bennylp $ */ - -#ifndef __PJ_STRING_H__ -#define __PJ_STRING_H__ - -/** - * @file string.h - * @brief PJLIB String Operations. - */ - -#include -#include - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_PSTR String Operations - * @ingroup PJ_DS - * @{ - * This module provides string manipulation API. - * - * \section pj_pstr_not_null_sec PJLIB String is NOT Null Terminated! - * - * That is the first information that developers need to know. Instead - * of using normal C string, strings in PJLIB are represented as - * pj_str_t structure below: - * - *
- *   typedef struct pj_str_t
- *   {
- *       char      *ptr;
- *       pj_size_t  slen;
- *   } pj_str_t;
- * 
- * - * There are some advantages of using this approach: - * - the string can point to arbitrary location in memory even - * if the string in that location is not null terminated. This is - * most usefull for text parsing, where the parsed text can just - * point to the original text in the input. If we use C string, - * then we will have to copy the text portion from the input - * to a string variable. - * - because the length of the string is known, string copy operation - * can be made more efficient. - * - * Most of APIs in PJLIB that expect or return string will represent - * the string as pj_str_t instead of normal C string. - * - * \section pj_pstr_examples_sec Examples - * - * For some examples, please see: - * - @ref page_pjlib_string_test - */ - -/** - * Create string initializer from a normal C string. - * - * @param str Null terminated string to be stored. - * - * @return pj_str_t. - */ -PJ_IDECL(pj_str_t) pj_str(char *str); - -/** - * Create constant string from normal C string. - * - * @param str The string to be initialized. - * @param s Null terminated string. - * - * @return pj_str_t. - */ -PJ_INLINE(const pj_str_t*) pj_cstr(pj_str_t *str, const char *s) -{ - str->ptr = (char*)s; - str->slen = s ? strlen(s) : 0; - return str; -} - -/** - * Set the pointer and length to the specified value. - * - * @param str the string. - * @param ptr pointer to set. - * @param length length to set. - * - * @return the string. - */ -PJ_INLINE(pj_str_t*) pj_strset( pj_str_t *str, char *ptr, pj_size_t length) -{ - str->ptr = ptr; - str->slen = length; - return str; -} - -/** - * Set the pointer and length of the string to the source string, which - * must be NULL terminated. - * - * @param str the string. - * @param src pointer to set. - * - * @return the string. - */ -PJ_INLINE(pj_str_t*) pj_strset2( pj_str_t *str, char *src) -{ - str->ptr = src; - str->slen = src ? strlen(src) : 0; - return str; -} - -/** - * Set the pointer and the length of the string. - * - * @param str The target string. - * @param begin The start of the string. - * @param end The end of the string. - * - * @return the target string. - */ -PJ_INLINE(pj_str_t*) pj_strset3( pj_str_t *str, char *begin, char *end ) -{ - str->ptr = begin; - str->slen = end-begin; - return str; -} - -/** - * Assign string. - * - * @param dst The target string. - * @param src The source string. - * - * @return the target string. - */ -PJ_IDECL(pj_str_t*) pj_strassign( pj_str_t *dst, pj_str_t *src ); - -/** - * Copy string contents. - * - * @param dst The target string. - * @param src The source string. - * - * @return the target string. - */ -PJ_IDECL(pj_str_t*) pj_strcpy(pj_str_t *dst, const pj_str_t *src); - -/** - * Copy string contents. - * - * @param dst The target string. - * @param src The source string. - * - * @return the target string. - */ -PJ_IDECL(pj_str_t*) pj_strcpy2(pj_str_t *dst, const char *src); - -/** - * Duplicate string. - * - * @param pool The pool. - * @param dst The string result. - * @param src The string to duplicate. - * - * @return the string result. - */ -PJ_IDECL(pj_str_t*) pj_strdup(pj_pool_t *pool, - pj_str_t *dst, - const pj_str_t *src); - -/** - * Duplicate string and NULL terminate the destination string. - * - * @param pool - * @param dst - * @param src - */ -PJ_IDECL(pj_str_t*) pj_strdup_with_null(pj_pool_t *pool, - pj_str_t *dst, - const pj_str_t *src); - -/** - * Duplicate string. - * - * @param pool The pool. - * @param dst The string result. - * @param src The string to duplicate. - * - * @return the string result. - */ -PJ_IDECL(pj_str_t*) pj_strdup2(pj_pool_t *pool, - pj_str_t *dst, - const char *src); - -/** - * Duplicate string. - * - * @param pool The pool. - * @param src The string to duplicate. - * - * @return the string result. - */ -PJ_IDECL(pj_str_t) pj_strdup3(pj_pool_t *pool, const char *src); - -/** - * Return the length of the string. - * - * @param str The string. - * - * @return the length of the string. - */ -PJ_INLINE(pj_size_t) pj_strlen( const pj_str_t *str ) -{ - return str->slen; -} - -/** - * Return the pointer to the string data. - * - * @param str The string. - * - * @return the pointer to the string buffer. - */ -PJ_INLINE(const char*) pj_strbuf( const pj_str_t *str ) -{ - return str->ptr; -} - -/** - * Compare strings. - * - * @param str1 The string to compare. - * @param str2 The string to compare. - * - * @return - * - < 0 if str1 is less than str2 - * - 0 if str1 is identical to str2 - * - > 0 if str1 is greater than str2 - */ -PJ_IDECL(int) pj_strcmp( const pj_str_t *str1, const pj_str_t *str2); - -/** - * Compare strings. - * - * @param str1 The string to compare. - * @param str2 The string to compare. - * - * @return - * - < 0 if str1 is less than str2 - * - 0 if str1 is identical to str2 - * - > 0 if str1 is greater than str2 - */ -PJ_IDECL(int) pj_strcmp2( const pj_str_t *str1, const char *str2 ); - -/** - * Compare strings. - * - * @param str1 The string to compare. - * @param str2 The string to compare. - * @param len The maximum number of characters to compare. - * - * @return - * - < 0 if str1 is less than str2 - * - 0 if str1 is identical to str2 - * - > 0 if str1 is greater than str2 - */ -PJ_IDECL(int) pj_strncmp( const pj_str_t *str1, const pj_str_t *str2, - pj_size_t len); - -/** - * Compare strings. - * - * @param str1 The string to compare. - * @param str2 The string to compare. - * @param len The maximum number of characters to compare. - * - * @return - * - < 0 if str1 is less than str2 - * - 0 if str1 is identical to str2 - * - > 0 if str1 is greater than str2 - */ -PJ_IDECL(int) pj_strncmp2( const pj_str_t *str1, const char *str2, - pj_size_t len); - -/** - * Perform lowercase comparison to the strings. - * - * @param str1 The string to compare. - * @param str2 The string to compare. - * - * @return - * - < 0 if str1 is less than str2 - * - 0 if str1 is identical to str2 - * - > 0 if str1 is greater than str2 - */ -PJ_IDECL(int) pj_stricmp( const pj_str_t *str1, const pj_str_t *str2); - -/** - * Perform lowercase comparison to the strings. - * - * @param str1 The string to compare. - * @param str2 The string to compare. - * - * @return - * - < 0 if str1 is less than str2 - * - 0 if str1 is identical to str2 - * - > 0 if str1 is greater than str2 - */ -PJ_IDECL(int) pj_stricmp2( const pj_str_t *str1, const char *str2); - -/** - * Perform lowercase comparison to the strings. - * - * @param str1 The string to compare. - * @param str2 The string to compare. - * @param len The maximum number of characters to compare. - * - * @return - * - < 0 if str1 is less than str2 - * - 0 if str1 is identical to str2 - * - > 0 if str1 is greater than str2 - */ -PJ_IDECL(int) pj_strnicmp( const pj_str_t *str1, const pj_str_t *str2, - pj_size_t len); - -/** - * Perform lowercase comparison to the strings. - * - * @param str1 The string to compare. - * @param str2 The string to compare. - * @param len The maximum number of characters to compare. - * - * @return - * - < 0 if str1 is less than str2 - * - 0 if str1 is identical to str2 - * - > 0 if str1 is greater than str2 - */ -PJ_IDECL(int) pj_strnicmp2( const pj_str_t *str1, const char *str2, - pj_size_t len); - -/** - * Concatenate strings. - * - * @param dst The destination string. - * @param src The source string. - */ -PJ_IDECL(void) pj_strcat(pj_str_t *dst, const pj_str_t *src); - -/** - * Finds a character in a string. - * - * @param str The string. - * @param chr The character to find. - * - * @return the pointer to first character found, or NULL. - */ -PJ_INLINE(char*) pj_strchr( pj_str_t *str, int chr) -{ - return (char*) memchr(str->ptr, chr, str->slen); -} - -/** - * Remove (trim) leading whitespaces from the string. - * - * @param str The string. - * - * @return the string. - */ -PJ_DECL(pj_str_t*) pj_strltrim( pj_str_t *str ); - -/** - * Remove (trim) the trailing whitespaces from the string. - * - * @param str The string. - * - * @return the string. - */ -PJ_DECL(pj_str_t*) pj_strrtrim( pj_str_t *str ); - -/** - * Remove (trim) leading and trailing whitespaces from the string. - * - * @param str The string. - * - * @return the string. - */ -PJ_IDECL(pj_str_t*) pj_strtrim( pj_str_t *str ); - -/** - * Initialize the buffer with some random string. - * - * @param str the string to store the result. - * @param length the length of the random string to generate. - * - * @return the string. - */ -PJ_DECL(char*) pj_create_random_string(char *str, pj_size_t length); - -/** - * Convert string to unsigned integer. - * - * @param str the string. - * - * @return the unsigned integer. - */ -PJ_DECL(unsigned long) pj_strtoul(const pj_str_t *str); - -/** - * Utility to convert unsigned integer to string. Note that the - * string will be NULL terminated. - * - * @param val the unsigned integer value. - * @param buf the buffer - * - * @return the number of characters written - */ -PJ_DECL(int) pj_utoa(unsigned long val, char *buf); - -/** - * Convert unsigned integer to string with minimum digits. Note that the - * string will be NULL terminated. - * - * @param val The unsigned integer value. - * @param buf The buffer. - * @param min_dig Minimum digits to be printed, or zero to specify no - * minimum digit. - * @param pad The padding character to be put in front of the string - * when the digits is less than minimum. - * - * @return the number of characters written. - */ -PJ_DECL(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad); - -/** - * Fill the memory location with value. - * - * @param dst The destination buffer. - * @param c Character to set. - * @param size The number of characters. - * - * @return the value of dst. - */ -PJ_INLINE(void*) pj_memset(void *dst, int c, pj_size_t size) -{ - return memset(dst, c, size); -} - -/** - * Copy buffer. - * - * @param dst The destination buffer. - * @param src The source buffer. - * @param size The size to copy. - * - * @return the destination buffer. - */ -PJ_INLINE(void*) pj_memcpy(void *dst, const void *src, pj_size_t size) -{ - return memcpy(dst, src, size); -} - -/** - * Move memory. - * - * @param dst The destination buffer. - * @param src The source buffer. - * @param size The size to copy. - * - * @return the destination buffer. - */ -PJ_INLINE(void*) pj_memmove(void *dst, const void *src, pj_size_t size) -{ - return memmove(dst, src, size); -} - -/** - * Compare buffers. - * - * @param buf1 The first buffer. - * @param buf2 The second buffer. - * @param size The size to compare. - * - * @return negative, zero, or positive value. - */ -PJ_INLINE(int) pj_memcmp(const void *buf1, const void *buf2, pj_size_t size) -{ - return memcmp(buf1, buf2, size); -} - -/** - * Find character in the buffer. - * - * @param buf The buffer. - * @param c The character to find. - * @param size The size to check. - * - * @return the pointer to location where the character is found, or NULL if - * not found. - */ -PJ_INLINE(void*) pj_memchr(const void *buf, int c, pj_size_t size) -{ - return memchr(buf, c, size); -} - -/** - * @} - */ - -#if PJ_FUNCTIONS_ARE_INLINED -# include -#endif - -PJ_END_DECL - -#endif /* __PJ_STRING_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/string.h 8 10/14/05 12:26a Bennylp $ */ + +#ifndef __PJ_STRING_H__ +#define __PJ_STRING_H__ + +/** + * @file string.h + * @brief PJLIB String Operations. + */ + +#include +#include + +PJ_BEGIN_DECL + +/** + * @defgroup PJ_PSTR String Operations + * @ingroup PJ_DS + * @{ + * This module provides string manipulation API. + * + * \section pj_pstr_not_null_sec PJLIB String is NOT Null Terminated! + * + * That is the first information that developers need to know. Instead + * of using normal C string, strings in PJLIB are represented as + * pj_str_t structure below: + * + *
+ *   typedef struct pj_str_t
+ *   {
+ *       char      *ptr;
+ *       pj_size_t  slen;
+ *   } pj_str_t;
+ * 
+ * + * There are some advantages of using this approach: + * - the string can point to arbitrary location in memory even + * if the string in that location is not null terminated. This is + * most usefull for text parsing, where the parsed text can just + * point to the original text in the input. If we use C string, + * then we will have to copy the text portion from the input + * to a string variable. + * - because the length of the string is known, string copy operation + * can be made more efficient. + * + * Most of APIs in PJLIB that expect or return string will represent + * the string as pj_str_t instead of normal C string. + * + * \section pj_pstr_examples_sec Examples + * + * For some examples, please see: + * - @ref page_pjlib_string_test + */ + +/** + * Create string initializer from a normal C string. + * + * @param str Null terminated string to be stored. + * + * @return pj_str_t. + */ +PJ_IDECL(pj_str_t) pj_str(char *str); + +/** + * Create constant string from normal C string. + * + * @param str The string to be initialized. + * @param s Null terminated string. + * + * @return pj_str_t. + */ +PJ_INLINE(const pj_str_t*) pj_cstr(pj_str_t *str, const char *s) +{ + str->ptr = (char*)s; + str->slen = s ? strlen(s) : 0; + return str; +} + +/** + * Set the pointer and length to the specified value. + * + * @param str the string. + * @param ptr pointer to set. + * @param length length to set. + * + * @return the string. + */ +PJ_INLINE(pj_str_t*) pj_strset( pj_str_t *str, char *ptr, pj_size_t length) +{ + str->ptr = ptr; + str->slen = length; + return str; +} + +/** + * Set the pointer and length of the string to the source string, which + * must be NULL terminated. + * + * @param str the string. + * @param src pointer to set. + * + * @return the string. + */ +PJ_INLINE(pj_str_t*) pj_strset2( pj_str_t *str, char *src) +{ + str->ptr = src; + str->slen = src ? strlen(src) : 0; + return str; +} + +/** + * Set the pointer and the length of the string. + * + * @param str The target string. + * @param begin The start of the string. + * @param end The end of the string. + * + * @return the target string. + */ +PJ_INLINE(pj_str_t*) pj_strset3( pj_str_t *str, char *begin, char *end ) +{ + str->ptr = begin; + str->slen = end-begin; + return str; +} + +/** + * Assign string. + * + * @param dst The target string. + * @param src The source string. + * + * @return the target string. + */ +PJ_IDECL(pj_str_t*) pj_strassign( pj_str_t *dst, pj_str_t *src ); + +/** + * Copy string contents. + * + * @param dst The target string. + * @param src The source string. + * + * @return the target string. + */ +PJ_IDECL(pj_str_t*) pj_strcpy(pj_str_t *dst, const pj_str_t *src); + +/** + * Copy string contents. + * + * @param dst The target string. + * @param src The source string. + * + * @return the target string. + */ +PJ_IDECL(pj_str_t*) pj_strcpy2(pj_str_t *dst, const char *src); + +/** + * Duplicate string. + * + * @param pool The pool. + * @param dst The string result. + * @param src The string to duplicate. + * + * @return the string result. + */ +PJ_IDECL(pj_str_t*) pj_strdup(pj_pool_t *pool, + pj_str_t *dst, + const pj_str_t *src); + +/** + * Duplicate string and NULL terminate the destination string. + * + * @param pool + * @param dst + * @param src + */ +PJ_IDECL(pj_str_t*) pj_strdup_with_null(pj_pool_t *pool, + pj_str_t *dst, + const pj_str_t *src); + +/** + * Duplicate string. + * + * @param pool The pool. + * @param dst The string result. + * @param src The string to duplicate. + * + * @return the string result. + */ +PJ_IDECL(pj_str_t*) pj_strdup2(pj_pool_t *pool, + pj_str_t *dst, + const char *src); + +/** + * Duplicate string. + * + * @param pool The pool. + * @param src The string to duplicate. + * + * @return the string result. + */ +PJ_IDECL(pj_str_t) pj_strdup3(pj_pool_t *pool, const char *src); + +/** + * Return the length of the string. + * + * @param str The string. + * + * @return the length of the string. + */ +PJ_INLINE(pj_size_t) pj_strlen( const pj_str_t *str ) +{ + return str->slen; +} + +/** + * Return the pointer to the string data. + * + * @param str The string. + * + * @return the pointer to the string buffer. + */ +PJ_INLINE(const char*) pj_strbuf( const pj_str_t *str ) +{ + return str->ptr; +} + +/** + * Compare strings. + * + * @param str1 The string to compare. + * @param str2 The string to compare. + * + * @return + * - < 0 if str1 is less than str2 + * - 0 if str1 is identical to str2 + * - > 0 if str1 is greater than str2 + */ +PJ_IDECL(int) pj_strcmp( const pj_str_t *str1, const pj_str_t *str2); + +/** + * Compare strings. + * + * @param str1 The string to compare. + * @param str2 The string to compare. + * + * @return + * - < 0 if str1 is less than str2 + * - 0 if str1 is identical to str2 + * - > 0 if str1 is greater than str2 + */ +PJ_IDECL(int) pj_strcmp2( const pj_str_t *str1, const char *str2 ); + +/** + * Compare strings. + * + * @param str1 The string to compare. + * @param str2 The string to compare. + * @param len The maximum number of characters to compare. + * + * @return + * - < 0 if str1 is less than str2 + * - 0 if str1 is identical to str2 + * - > 0 if str1 is greater than str2 + */ +PJ_IDECL(int) pj_strncmp( const pj_str_t *str1, const pj_str_t *str2, + pj_size_t len); + +/** + * Compare strings. + * + * @param str1 The string to compare. + * @param str2 The string to compare. + * @param len The maximum number of characters to compare. + * + * @return + * - < 0 if str1 is less than str2 + * - 0 if str1 is identical to str2 + * - > 0 if str1 is greater than str2 + */ +PJ_IDECL(int) pj_strncmp2( const pj_str_t *str1, const char *str2, + pj_size_t len); + +/** + * Perform lowercase comparison to the strings. + * + * @param str1 The string to compare. + * @param str2 The string to compare. + * + * @return + * - < 0 if str1 is less than str2 + * - 0 if str1 is identical to str2 + * - > 0 if str1 is greater than str2 + */ +PJ_IDECL(int) pj_stricmp( const pj_str_t *str1, const pj_str_t *str2); + +/** + * Perform lowercase comparison to the strings. + * + * @param str1 The string to compare. + * @param str2 The string to compare. + * + * @return + * - < 0 if str1 is less than str2 + * - 0 if str1 is identical to str2 + * - > 0 if str1 is greater than str2 + */ +PJ_IDECL(int) pj_stricmp2( const pj_str_t *str1, const char *str2); + +/** + * Perform lowercase comparison to the strings. + * + * @param str1 The string to compare. + * @param str2 The string to compare. + * @param len The maximum number of characters to compare. + * + * @return + * - < 0 if str1 is less than str2 + * - 0 if str1 is identical to str2 + * - > 0 if str1 is greater than str2 + */ +PJ_IDECL(int) pj_strnicmp( const pj_str_t *str1, const pj_str_t *str2, + pj_size_t len); + +/** + * Perform lowercase comparison to the strings. + * + * @param str1 The string to compare. + * @param str2 The string to compare. + * @param len The maximum number of characters to compare. + * + * @return + * - < 0 if str1 is less than str2 + * - 0 if str1 is identical to str2 + * - > 0 if str1 is greater than str2 + */ +PJ_IDECL(int) pj_strnicmp2( const pj_str_t *str1, const char *str2, + pj_size_t len); + +/** + * Concatenate strings. + * + * @param dst The destination string. + * @param src The source string. + */ +PJ_IDECL(void) pj_strcat(pj_str_t *dst, const pj_str_t *src); + +/** + * Finds a character in a string. + * + * @param str The string. + * @param chr The character to find. + * + * @return the pointer to first character found, or NULL. + */ +PJ_INLINE(char*) pj_strchr( pj_str_t *str, int chr) +{ + return (char*) memchr(str->ptr, chr, str->slen); +} + +/** + * Remove (trim) leading whitespaces from the string. + * + * @param str The string. + * + * @return the string. + */ +PJ_DECL(pj_str_t*) pj_strltrim( pj_str_t *str ); + +/** + * Remove (trim) the trailing whitespaces from the string. + * + * @param str The string. + * + * @return the string. + */ +PJ_DECL(pj_str_t*) pj_strrtrim( pj_str_t *str ); + +/** + * Remove (trim) leading and trailing whitespaces from the string. + * + * @param str The string. + * + * @return the string. + */ +PJ_IDECL(pj_str_t*) pj_strtrim( pj_str_t *str ); + +/** + * Initialize the buffer with some random string. + * + * @param str the string to store the result. + * @param length the length of the random string to generate. + * + * @return the string. + */ +PJ_DECL(char*) pj_create_random_string(char *str, pj_size_t length); + +/** + * Convert string to unsigned integer. + * + * @param str the string. + * + * @return the unsigned integer. + */ +PJ_DECL(unsigned long) pj_strtoul(const pj_str_t *str); + +/** + * Utility to convert unsigned integer to string. Note that the + * string will be NULL terminated. + * + * @param val the unsigned integer value. + * @param buf the buffer + * + * @return the number of characters written + */ +PJ_DECL(int) pj_utoa(unsigned long val, char *buf); + +/** + * Convert unsigned integer to string with minimum digits. Note that the + * string will be NULL terminated. + * + * @param val The unsigned integer value. + * @param buf The buffer. + * @param min_dig Minimum digits to be printed, or zero to specify no + * minimum digit. + * @param pad The padding character to be put in front of the string + * when the digits is less than minimum. + * + * @return the number of characters written. + */ +PJ_DECL(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad); + +/** + * Fill the memory location with value. + * + * @param dst The destination buffer. + * @param c Character to set. + * @param size The number of characters. + * + * @return the value of dst. + */ +PJ_INLINE(void*) pj_memset(void *dst, int c, pj_size_t size) +{ + return memset(dst, c, size); +} + +/** + * Copy buffer. + * + * @param dst The destination buffer. + * @param src The source buffer. + * @param size The size to copy. + * + * @return the destination buffer. + */ +PJ_INLINE(void*) pj_memcpy(void *dst, const void *src, pj_size_t size) +{ + return memcpy(dst, src, size); +} + +/** + * Move memory. + * + * @param dst The destination buffer. + * @param src The source buffer. + * @param size The size to copy. + * + * @return the destination buffer. + */ +PJ_INLINE(void*) pj_memmove(void *dst, const void *src, pj_size_t size) +{ + return memmove(dst, src, size); +} + +/** + * Compare buffers. + * + * @param buf1 The first buffer. + * @param buf2 The second buffer. + * @param size The size to compare. + * + * @return negative, zero, or positive value. + */ +PJ_INLINE(int) pj_memcmp(const void *buf1, const void *buf2, pj_size_t size) +{ + return memcmp(buf1, buf2, size); +} + +/** + * Find character in the buffer. + * + * @param buf The buffer. + * @param c The character to find. + * @param size The size to check. + * + * @return the pointer to location where the character is found, or NULL if + * not found. + */ +PJ_INLINE(void*) pj_memchr(const void *buf, int c, pj_size_t size) +{ + return memchr(buf, c, size); +} + +/** + * @} + */ + +#if PJ_FUNCTIONS_ARE_INLINED +# include +#endif + +PJ_END_DECL + +#endif /* __PJ_STRING_H__ */ + diff --git a/pjlib/include/pj/string_i.h b/pjlib/include/pj/string_i.h index 0c60623b..17e6255d 100644 --- a/pjlib/include/pj/string_i.h +++ b/pjlib/include/pj/string_i.h @@ -1,162 +1,162 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/string_i.h 8 10/14/05 12:26a Bennylp $ */ - -PJ_IDEF(pj_str_t) pj_str(char *str) -{ - pj_str_t dst; - dst.ptr = str; - dst.slen = str ? strlen(str) : 0; - return dst; -} - -PJ_IDEF(pj_str_t*) pj_strdup(pj_pool_t *pool, - pj_str_t *dst, - const pj_str_t *src) -{ - if (src->slen) { - dst->ptr = (char*)pj_pool_alloc(pool, src->slen); - pj_memcpy(dst->ptr, src->ptr, src->slen); - } - dst->slen = src->slen; - return dst; -} - -PJ_IDEF(pj_str_t*) pj_strdup_with_null( pj_pool_t *pool, - pj_str_t *dst, - const pj_str_t *src) -{ - if (src->slen) { - dst->ptr = (char*)pj_pool_alloc(pool, src->slen+1); - pj_memcpy(dst->ptr, src->ptr, src->slen); - } else { - dst->ptr = (char*)pj_pool_alloc(pool, 1); - } - dst->slen = src->slen; - dst->ptr[dst->slen] = '\0'; - return dst; -} - -PJ_IDEF(pj_str_t*) pj_strdup2(pj_pool_t *pool, - pj_str_t *dst, - const char *src) -{ - dst->slen = src ? strlen(src) : 0; - if (dst->slen) { - dst->ptr = (char*)pj_pool_alloc(pool, dst->slen); - pj_memcpy(dst->ptr, src, dst->slen); - } else { - dst->ptr = NULL; - } - return dst; -} - - -PJ_IDEF(pj_str_t) pj_strdup3(pj_pool_t *pool, const char *src) -{ - pj_str_t temp; - pj_strdup2(pool, &temp, src); - return temp; -} - -PJ_IDEF(pj_str_t*) pj_strassign( pj_str_t *dst, pj_str_t *src ) -{ - dst->ptr = src->ptr; - dst->slen = src->slen; - return dst; -} - -PJ_IDEF(pj_str_t*) pj_strcpy(pj_str_t *dst, const pj_str_t *src) -{ - dst->slen = src->slen; - if (src->slen > 0) - pj_memcpy(dst->ptr, src->ptr, src->slen); - return dst; -} - -PJ_IDEF(pj_str_t*) pj_strcpy2(pj_str_t *dst, const char *src) -{ - dst->slen = src ? strlen(src) : 0; - if (dst->slen > 0) - pj_memcpy(dst->ptr, src, dst->slen); - return dst; -} - -PJ_IDEF(int) pj_strcmp( const pj_str_t *str1, const pj_str_t *str2) -{ - pj_ssize_t diff; - - diff = str1->slen - str2->slen; - if (diff) { - return (int)diff; - } else if (str1->ptr) { - return strncmp(str1->ptr, str2->ptr, str1->slen); - } else { - return 0; - } -} - -PJ_IDEF(int) pj_strncmp( const pj_str_t *str1, const pj_str_t *str2, - pj_size_t len) -{ - return (str1->ptr && str2->ptr) ? strncmp(str1->ptr, str2->ptr, len) : - (str1->ptr == str2->ptr ? 0 : 1); -} - -PJ_IDEF(int) pj_strncmp2( const pj_str_t *str1, const char *str2, - pj_size_t len) -{ - return (str1->ptr && str2) ? strncmp(str1->ptr, str2, len) : - (str1->ptr==str2 ? 0 : 1); -} - -PJ_IDEF(int) pj_strcmp2( const pj_str_t *str1, const char *str2 ) -{ - return pj_strncmp2( str1, str2, str1->slen); -} - -PJ_IDEF(int) pj_stricmp( const pj_str_t *str1, const pj_str_t *str2) -{ - pj_ssize_t diff; - - diff = str1->slen - str2->slen; - if (diff) { - return (int)diff; - } else { - return strnicmp(str1->ptr, str2->ptr, str1->slen); - } -} - -PJ_IDEF(int) pj_stricmp2( const pj_str_t *str1, const char *str2) -{ - return (str1->ptr && str2) ? strnicmp(str1->ptr, str2, str1->slen) : - (str1->ptr==str2 ? 0 : 1); -} - -PJ_IDEF(int) pj_strnicmp( const pj_str_t *str1, const pj_str_t *str2, - pj_size_t len) -{ - return (str1->ptr && str2->ptr) ? strnicmp(str1->ptr, str2->ptr, len) : - (str1->ptr == str2->ptr ? 0 : 1); -} - -PJ_IDEF(int) pj_strnicmp2( const pj_str_t *str1, const char *str2, - pj_size_t len) -{ - return (str1->ptr && str2) ? strnicmp(str1->ptr, str2, len) : - (str1->ptr == str2 ? 0 : 1); -} - -PJ_IDEF(void) pj_strcat(pj_str_t *dst, const pj_str_t *src) -{ - if (src->slen) { - pj_memcpy(dst->ptr + dst->slen, src->ptr, src->slen); - dst->slen += src->slen; - } -} - -PJ_IDEF(pj_str_t*) pj_strtrim( pj_str_t *str ) -{ - pj_strltrim(str); - pj_strrtrim(str); - return str; -} - +/* $Header: /pjproject-0.3/pjlib/include/pj/string_i.h 8 10/14/05 12:26a Bennylp $ */ + +PJ_IDEF(pj_str_t) pj_str(char *str) +{ + pj_str_t dst; + dst.ptr = str; + dst.slen = str ? strlen(str) : 0; + return dst; +} + +PJ_IDEF(pj_str_t*) pj_strdup(pj_pool_t *pool, + pj_str_t *dst, + const pj_str_t *src) +{ + if (src->slen) { + dst->ptr = (char*)pj_pool_alloc(pool, src->slen); + pj_memcpy(dst->ptr, src->ptr, src->slen); + } + dst->slen = src->slen; + return dst; +} + +PJ_IDEF(pj_str_t*) pj_strdup_with_null( pj_pool_t *pool, + pj_str_t *dst, + const pj_str_t *src) +{ + if (src->slen) { + dst->ptr = (char*)pj_pool_alloc(pool, src->slen+1); + pj_memcpy(dst->ptr, src->ptr, src->slen); + } else { + dst->ptr = (char*)pj_pool_alloc(pool, 1); + } + dst->slen = src->slen; + dst->ptr[dst->slen] = '\0'; + return dst; +} + +PJ_IDEF(pj_str_t*) pj_strdup2(pj_pool_t *pool, + pj_str_t *dst, + const char *src) +{ + dst->slen = src ? strlen(src) : 0; + if (dst->slen) { + dst->ptr = (char*)pj_pool_alloc(pool, dst->slen); + pj_memcpy(dst->ptr, src, dst->slen); + } else { + dst->ptr = NULL; + } + return dst; +} + + +PJ_IDEF(pj_str_t) pj_strdup3(pj_pool_t *pool, const char *src) +{ + pj_str_t temp; + pj_strdup2(pool, &temp, src); + return temp; +} + +PJ_IDEF(pj_str_t*) pj_strassign( pj_str_t *dst, pj_str_t *src ) +{ + dst->ptr = src->ptr; + dst->slen = src->slen; + return dst; +} + +PJ_IDEF(pj_str_t*) pj_strcpy(pj_str_t *dst, const pj_str_t *src) +{ + dst->slen = src->slen; + if (src->slen > 0) + pj_memcpy(dst->ptr, src->ptr, src->slen); + return dst; +} + +PJ_IDEF(pj_str_t*) pj_strcpy2(pj_str_t *dst, const char *src) +{ + dst->slen = src ? strlen(src) : 0; + if (dst->slen > 0) + pj_memcpy(dst->ptr, src, dst->slen); + return dst; +} + +PJ_IDEF(int) pj_strcmp( const pj_str_t *str1, const pj_str_t *str2) +{ + pj_ssize_t diff; + + diff = str1->slen - str2->slen; + if (diff) { + return (int)diff; + } else if (str1->ptr) { + return strncmp(str1->ptr, str2->ptr, str1->slen); + } else { + return 0; + } +} + +PJ_IDEF(int) pj_strncmp( const pj_str_t *str1, const pj_str_t *str2, + pj_size_t len) +{ + return (str1->ptr && str2->ptr) ? strncmp(str1->ptr, str2->ptr, len) : + (str1->ptr == str2->ptr ? 0 : 1); +} + +PJ_IDEF(int) pj_strncmp2( const pj_str_t *str1, const char *str2, + pj_size_t len) +{ + return (str1->ptr && str2) ? strncmp(str1->ptr, str2, len) : + (str1->ptr==str2 ? 0 : 1); +} + +PJ_IDEF(int) pj_strcmp2( const pj_str_t *str1, const char *str2 ) +{ + return pj_strncmp2( str1, str2, str1->slen); +} + +PJ_IDEF(int) pj_stricmp( const pj_str_t *str1, const pj_str_t *str2) +{ + pj_ssize_t diff; + + diff = str1->slen - str2->slen; + if (diff) { + return (int)diff; + } else { + return strnicmp(str1->ptr, str2->ptr, str1->slen); + } +} + +PJ_IDEF(int) pj_stricmp2( const pj_str_t *str1, const char *str2) +{ + return (str1->ptr && str2) ? strnicmp(str1->ptr, str2, str1->slen) : + (str1->ptr==str2 ? 0 : 1); +} + +PJ_IDEF(int) pj_strnicmp( const pj_str_t *str1, const pj_str_t *str2, + pj_size_t len) +{ + return (str1->ptr && str2->ptr) ? strnicmp(str1->ptr, str2->ptr, len) : + (str1->ptr == str2->ptr ? 0 : 1); +} + +PJ_IDEF(int) pj_strnicmp2( const pj_str_t *str1, const char *str2, + pj_size_t len) +{ + return (str1->ptr && str2) ? strnicmp(str1->ptr, str2, len) : + (str1->ptr == str2 ? 0 : 1); +} + +PJ_IDEF(void) pj_strcat(pj_str_t *dst, const pj_str_t *src) +{ + if (src->slen) { + pj_memcpy(dst->ptr + dst->slen, src->ptr, src->slen); + dst->slen += src->slen; + } +} + +PJ_IDEF(pj_str_t*) pj_strtrim( pj_str_t *str ) +{ + pj_strltrim(str); + pj_strrtrim(str); + return str; +} + diff --git a/pjlib/include/pj/stun.h b/pjlib/include/pj/stun.h index 999dda42..90c20ec6 100644 --- a/pjlib/include/pj/stun.h +++ b/pjlib/include/pj/stun.h @@ -1,123 +1,123 @@ -#ifndef __PJ_STUN_H__ -#define __PJ_STUN_H__ - -#include -#include - -PJ_BEGIN_DECL - -#define PJ_STUN_MAX_ATTR 16 - -typedef enum pj_stun_msg_type -{ - PJ_STUN_BINDING_REQUEST = 0x0001, - PJ_STUN_BINDING_RESPONSE = 0x0101, - PJ_STUN_BINDING_ERROR_RESPONSE = 0x0111, - PJ_STUN_SHARED_SECRET_REQUEST = 0x0002, - PJ_STUN_SHARED_SECRET_RESPONSE = 0x0102, - PJ_STUN_SHARED_SECRET_ERROR_RESPONSE = 0x0112 -} pj_stun_msg_type; - -typedef enum pj_stun_attr_type -{ - PJ_STUN_ATTR_MAPPED_ADDR = 1, - PJ_STUN_ATTR_RESPONSE_ADDR, - PJ_STUN_ATTR_CHANGE_REQUEST, - PJ_STUN_ATTR_SOURCE_ADDR, - PJ_STUN_ATTR_CHANGED_ADDR, - PJ_STUN_ATTR_USERNAME, - PJ_STUN_ATTR_PASSWORD, - PJ_STUN_ATTR_MESSAGE_INTEGRITY, - PJ_STUN_ATTR_ERROR_CODE, - PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES, - PJ_STUN_ATTR_REFLECTED_FORM -} pj_stun_attr_type; - -typedef struct pj_stun_msg_hdr -{ - pj_uint16_t type; - pj_uint16_t length; - pj_uint32_t tsx[4]; -} pj_stun_msg_hdr; - -typedef struct pj_stun_attr_hdr -{ - pj_uint16_t type; - pj_uint16_t length; -} pj_stun_attr_hdr; - -typedef struct pj_stun_mapped_addr_attr -{ - pj_stun_attr_hdr hdr; - pj_uint8_t ignored; - pj_uint8_t family; - pj_uint16_t port; - pj_uint32_t addr; -} pj_stun_mapped_addr_attr; - -typedef pj_stun_mapped_addr_attr pj_stun_response_addr_attr; -typedef pj_stun_mapped_addr_attr pj_stun_changed_addr_attr; -typedef pj_stun_mapped_addr_attr pj_stun_src_addr_attr; -typedef pj_stun_mapped_addr_attr pj_stun_reflected_form_attr; - -typedef struct pj_stun_change_request_attr -{ - pj_stun_attr_hdr hdr; - pj_uint32_t value; -} pj_stun_change_request_attr; - -typedef struct pj_stun_username_attr -{ - pj_stun_attr_hdr hdr; - pj_uint32_t value[1]; -} pj_stun_username_attr; - -typedef pj_stun_username_attr pj_stun_password_attr; - -typedef struct pj_stun_error_code_attr -{ - pj_stun_attr_hdr hdr; - pj_uint16_t ignored; - pj_uint8_t err_class; - pj_uint8_t number; - char reason[4]; -} pj_stun_error_code_attr; - -typedef struct pj_stun_msg -{ - pj_stun_msg_hdr *hdr; - int attr_count; - pj_stun_attr_hdr *attr[PJ_STUN_MAX_ATTR]; -} pj_stun_msg; - -/* STUN message API (stun.c). */ - -PJ_DECL(pj_status_t) pj_stun_create_bind_req( pj_pool_t *pool, - void **msg, pj_size_t *len, - pj_uint32_t id_hi, - pj_uint32_t id_lo); -PJ_DECL(pj_status_t) pj_stun_parse_msg( void *buf, pj_size_t len, - pj_stun_msg *msg); -PJ_DECL(void*) pj_stun_msg_find_attr( pj_stun_msg *msg, pj_stun_attr_type t); - -/* STUN simple client API (stun_client.c) */ -enum pj_stun_err_code { - PJ_STUN_ERR_MEMORY = (-2), - PJ_STUN_ERR_RESOLVE = (-3), - PJ_STUN_ERR_TRANSPORT = (-4), - PJ_STUN_ERR_INVALID_MSG = (-5), - PJ_STUN_ERR_NO_RESPONSE = (-6), - PJ_STUN_ERR_SYMETRIC = (-7), -}; - -PJ_DECL(pj_status_t) pj_stun_get_mapped_addr( pj_pool_factory *pf, - int sock_cnt, pj_sock_t sock[], - const pj_str_t *srv1, int port1, - const pj_str_t *srv2, int port2, - pj_sockaddr_in mapped_addr[]); -PJ_DECL(const char*) pj_stun_get_err_msg(pj_status_t status); - -PJ_END_DECL - -#endif /* __PJ_STUN_H__ */ - +#ifndef __PJ_STUN_H__ +#define __PJ_STUN_H__ + +#include +#include + +PJ_BEGIN_DECL + +#define PJ_STUN_MAX_ATTR 16 + +typedef enum pj_stun_msg_type +{ + PJ_STUN_BINDING_REQUEST = 0x0001, + PJ_STUN_BINDING_RESPONSE = 0x0101, + PJ_STUN_BINDING_ERROR_RESPONSE = 0x0111, + PJ_STUN_SHARED_SECRET_REQUEST = 0x0002, + PJ_STUN_SHARED_SECRET_RESPONSE = 0x0102, + PJ_STUN_SHARED_SECRET_ERROR_RESPONSE = 0x0112 +} pj_stun_msg_type; + +typedef enum pj_stun_attr_type +{ + PJ_STUN_ATTR_MAPPED_ADDR = 1, + PJ_STUN_ATTR_RESPONSE_ADDR, + PJ_STUN_ATTR_CHANGE_REQUEST, + PJ_STUN_ATTR_SOURCE_ADDR, + PJ_STUN_ATTR_CHANGED_ADDR, + PJ_STUN_ATTR_USERNAME, + PJ_STUN_ATTR_PASSWORD, + PJ_STUN_ATTR_MESSAGE_INTEGRITY, + PJ_STUN_ATTR_ERROR_CODE, + PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES, + PJ_STUN_ATTR_REFLECTED_FORM +} pj_stun_attr_type; + +typedef struct pj_stun_msg_hdr +{ + pj_uint16_t type; + pj_uint16_t length; + pj_uint32_t tsx[4]; +} pj_stun_msg_hdr; + +typedef struct pj_stun_attr_hdr +{ + pj_uint16_t type; + pj_uint16_t length; +} pj_stun_attr_hdr; + +typedef struct pj_stun_mapped_addr_attr +{ + pj_stun_attr_hdr hdr; + pj_uint8_t ignored; + pj_uint8_t family; + pj_uint16_t port; + pj_uint32_t addr; +} pj_stun_mapped_addr_attr; + +typedef pj_stun_mapped_addr_attr pj_stun_response_addr_attr; +typedef pj_stun_mapped_addr_attr pj_stun_changed_addr_attr; +typedef pj_stun_mapped_addr_attr pj_stun_src_addr_attr; +typedef pj_stun_mapped_addr_attr pj_stun_reflected_form_attr; + +typedef struct pj_stun_change_request_attr +{ + pj_stun_attr_hdr hdr; + pj_uint32_t value; +} pj_stun_change_request_attr; + +typedef struct pj_stun_username_attr +{ + pj_stun_attr_hdr hdr; + pj_uint32_t value[1]; +} pj_stun_username_attr; + +typedef pj_stun_username_attr pj_stun_password_attr; + +typedef struct pj_stun_error_code_attr +{ + pj_stun_attr_hdr hdr; + pj_uint16_t ignored; + pj_uint8_t err_class; + pj_uint8_t number; + char reason[4]; +} pj_stun_error_code_attr; + +typedef struct pj_stun_msg +{ + pj_stun_msg_hdr *hdr; + int attr_count; + pj_stun_attr_hdr *attr[PJ_STUN_MAX_ATTR]; +} pj_stun_msg; + +/* STUN message API (stun.c). */ + +PJ_DECL(pj_status_t) pj_stun_create_bind_req( pj_pool_t *pool, + void **msg, pj_size_t *len, + pj_uint32_t id_hi, + pj_uint32_t id_lo); +PJ_DECL(pj_status_t) pj_stun_parse_msg( void *buf, pj_size_t len, + pj_stun_msg *msg); +PJ_DECL(void*) pj_stun_msg_find_attr( pj_stun_msg *msg, pj_stun_attr_type t); + +/* STUN simple client API (stun_client.c) */ +enum pj_stun_err_code { + PJ_STUN_ERR_MEMORY = (-2), + PJ_STUN_ERR_RESOLVE = (-3), + PJ_STUN_ERR_TRANSPORT = (-4), + PJ_STUN_ERR_INVALID_MSG = (-5), + PJ_STUN_ERR_NO_RESPONSE = (-6), + PJ_STUN_ERR_SYMETRIC = (-7), +}; + +PJ_DECL(pj_status_t) pj_stun_get_mapped_addr( pj_pool_factory *pf, + int sock_cnt, pj_sock_t sock[], + const pj_str_t *srv1, int port1, + const pj_str_t *srv2, int port2, + pj_sockaddr_in mapped_addr[]); +PJ_DECL(const char*) pj_stun_get_err_msg(pj_status_t status); + +PJ_END_DECL + +#endif /* __PJ_STUN_H__ */ + diff --git a/pjlib/include/pj/timer.h b/pjlib/include/pj/timer.h index 03e4be3f..0fb5588c 100644 --- a/pjlib/include/pj/timer.h +++ b/pjlib/include/pj/timer.h @@ -1,237 +1,237 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/timer.h 7 10/14/05 12:26a Bennylp $ */ -/* (C)1993-2003 Douglas C. Schmidt - * - * This file is originaly from ACE library by Doug Schmidt - * ACE(TM), TAO(TM) and CIAO(TM) are copyrighted by Douglas C. Schmidt and his research - * group at Washington University, University of California, Irvine, and Vanderbilt - * University Copyright (c) 1993-2003, all rights reserved. - * - */ - -#ifndef __PJ_TIMER_H__ -#define __PJ_TIMER_H__ - -/** - * @file timer.h - * @brief Timer Heap - */ - -#include - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_TIMER Timer Heap Management. - * @ingroup PJ_MISC - * @brief - * The timer scheduling implementation here is based on ACE library's - * ACE_Timer_Heap, with only little modification to suit our library's style - * (I even left most of the comments in the original source). - * - * To quote the original quote in ACE_Timer_Heap_T class: - * - * This implementation uses a heap-based callout queue of - * absolute times. Therefore, in the average and worst case, - * scheduling, canceling, and expiring timers is O(log N) (where - * N is the total number of timers). In addition, we can also - * preallocate as many \a ACE_Timer_Nodes as there are slots in - * the heap. This allows us to completely remove the need for - * dynamic memory allocation, which is important for real-time - * systems. - * @{ - * - * \section pj_timer_examples_sec Examples - * - * For some examples on how to use the timer heap, please see the link below. - * - * - \ref page_pjlib_timer_test - */ - - -/** - * The type for internal timer ID. - */ -typedef int pj_timer_id_t; - -/** - * Forward declaration for pj_timer_entry. - */ -struct pj_timer_entry; - -/** - * The type of callback function to be called by timer scheduler when a timer - * has expired. - * - * @param timer_heap The timer heap. - * @param entry Timer entry which timer's has expired. - */ -typedef void pj_timer_heap_callback(pj_timer_heap_t *timer_heap, - struct pj_timer_entry *entry); - - -/** - * This structure represents an entry to the timer. - */ -struct pj_timer_entry -{ - /** - * User data to be associated with this entry. - * Applications normally will put the instance of object that - * owns the timer entry in this field. - */ - void *user_data; - - /** - * Arbitrary ID assigned by the user/owner of this entry. - * Applications can use this ID to distinguish multiple - * timer entries that share the same callback and user_data. - */ - int id; - - /** - * Callback to be called when the timer expires. - */ - pj_timer_heap_callback *cb; - - /** - * Internal unique timer ID, which is assigned by the timer heap. - * Application should not touch this ID. - */ - pj_timer_id_t _timer_id; - - /** - * The future time when the timer expires, which the value is updated - * by timer heap when the timer is scheduled. - */ - pj_time_val _timer_value; -}; - - -/** - * Default flag for timer heap, indicates that synchronization will be - * used. - */ -#define PJ_TIMER_HEAP_SYNCHRONIZE (0) - -/** - * Flag to indicate that thread synchronization is NOT needed for the - * timer heap. - */ -#define PJ_TIMER_HEAP_NO_SYNCHRONIZE (1) - -/** - * Calculate memory size required to create a timer heap. - * - * @param count Number of timer entries to be supported. - * @return Memory size requirement in bytes. - */ -PJ_DECL(pj_size_t) pj_timer_heap_mem_size(pj_size_t count); - -/** - * Create a timer heap. - * - * @param pool The pool where allocations in the timer heap will be - * allocated. The timer heap will dynamicly allocate - * more storate from the pool if the number of timer - * entries registered is more than the size originally - * requested when calling this function. - * @param count The maximum number of timer entries to be supported - * initially. If the application registers more entries - * during runtime, then the timer heap will resize. - * @param flag Creation flag, currently only PJ_TIMER_HEAP_NO_SYNCHRONIZE - * is recognized.. - * @param ht Pointer to receive the created timer heap. - * - * @return PJ_SUCCESS, or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_timer_heap_create( pj_pool_t *pool, - pj_size_t count, - unsigned flag, - pj_timer_heap_t **ht); - -/** - * Initialize a timer entry. Application should call this function at least - * once before scheduling the entry to the timer heap, to properly initialize - * the timer entry. - * - * @param entry The timer entry to be initialized. - * @param id Arbitrary ID assigned by the user/owner of this entry. - * Applications can use this ID to distinguish multiple - * timer entries that share the same callback and user_data. - * @param user_data User data to be associated with this entry. - * Applications normally will put the instance of object that - * owns the timer entry in this field. - * @param cb Callback function to be called when the timer elapses. - * - * @return The timer entry itself. - */ -PJ_DECL(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry, - int id, - void *user_data, - pj_timer_heap_callback *cb ); - -/** - * Schedule a timer entry which will expire AFTER the specified delay. - * - * @param ht The timer heap. - * @param entry The entry to be registered. - * @param delay The interval to expire. - * @return PJ_SUCCESS, or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht, - pj_timer_entry *entry, - const pj_time_val *delay); - -/** - * Cancel a previously registered timer. - * - * @param ht The timer heap. - * @param entry The entry to be cancelled. - * @return The number of timer cancelled, which should be one if the - * entry has really been registered, or zero if no timer was - * cancelled. - */ -PJ_DECL(int) pj_timer_heap_cancel( pj_timer_heap_t *ht, - pj_timer_entry *entry); - -/** - * Get the number of timer entries. - * - * @param ht The timer heap. - * @return The number of timer entries. - */ -PJ_DECL(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht ); - -/** - * Get the earliest time registered in the timer heap. The timer heap - * MUST have at least one timer being scheduled (application should use - * #pj_timer_heap_count() before calling this function). - * - * @param ht The timer heap. - * @param timeval The time deadline of the earliest timer entry. - * - * @return PJ_SUCCESS, or PJ_ENOTFOUND if no entry is scheduled. - */ -PJ_DECL(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t *ht, - pj_time_val *timeval); - -/** - * Poll the timer heap, check for expired timers and call the callback for - * each of the expired timers. - * - * @param ht The timer heap. - * @param next_delay If this parameter is not NULL, it will be filled up with - * the time delay until the next timer elapsed, or -1 in - * the sec part if no entry exist. - * @return The number of timers expired. - */ -PJ_DECL(int) pj_timer_heap_poll( pj_timer_heap_t *ht, pj_time_val *next_delay); - -/** - * @} - */ - -PJ_END_DECL - -#endif /* __PJ_TIMER_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/timer.h 7 10/14/05 12:26a Bennylp $ */ +/* (C)1993-2003 Douglas C. Schmidt + * + * This file is originaly from ACE library by Doug Schmidt + * ACE(TM), TAO(TM) and CIAO(TM) are copyrighted by Douglas C. Schmidt and his research + * group at Washington University, University of California, Irvine, and Vanderbilt + * University Copyright (c) 1993-2003, all rights reserved. + * + */ + +#ifndef __PJ_TIMER_H__ +#define __PJ_TIMER_H__ + +/** + * @file timer.h + * @brief Timer Heap + */ + +#include + +PJ_BEGIN_DECL + +/** + * @defgroup PJ_TIMER Timer Heap Management. + * @ingroup PJ_MISC + * @brief + * The timer scheduling implementation here is based on ACE library's + * ACE_Timer_Heap, with only little modification to suit our library's style + * (I even left most of the comments in the original source). + * + * To quote the original quote in ACE_Timer_Heap_T class: + * + * This implementation uses a heap-based callout queue of + * absolute times. Therefore, in the average and worst case, + * scheduling, canceling, and expiring timers is O(log N) (where + * N is the total number of timers). In addition, we can also + * preallocate as many \a ACE_Timer_Nodes as there are slots in + * the heap. This allows us to completely remove the need for + * dynamic memory allocation, which is important for real-time + * systems. + * @{ + * + * \section pj_timer_examples_sec Examples + * + * For some examples on how to use the timer heap, please see the link below. + * + * - \ref page_pjlib_timer_test + */ + + +/** + * The type for internal timer ID. + */ +typedef int pj_timer_id_t; + +/** + * Forward declaration for pj_timer_entry. + */ +struct pj_timer_entry; + +/** + * The type of callback function to be called by timer scheduler when a timer + * has expired. + * + * @param timer_heap The timer heap. + * @param entry Timer entry which timer's has expired. + */ +typedef void pj_timer_heap_callback(pj_timer_heap_t *timer_heap, + struct pj_timer_entry *entry); + + +/** + * This structure represents an entry to the timer. + */ +struct pj_timer_entry +{ + /** + * User data to be associated with this entry. + * Applications normally will put the instance of object that + * owns the timer entry in this field. + */ + void *user_data; + + /** + * Arbitrary ID assigned by the user/owner of this entry. + * Applications can use this ID to distinguish multiple + * timer entries that share the same callback and user_data. + */ + int id; + + /** + * Callback to be called when the timer expires. + */ + pj_timer_heap_callback *cb; + + /** + * Internal unique timer ID, which is assigned by the timer heap. + * Application should not touch this ID. + */ + pj_timer_id_t _timer_id; + + /** + * The future time when the timer expires, which the value is updated + * by timer heap when the timer is scheduled. + */ + pj_time_val _timer_value; +}; + + +/** + * Default flag for timer heap, indicates that synchronization will be + * used. + */ +#define PJ_TIMER_HEAP_SYNCHRONIZE (0) + +/** + * Flag to indicate that thread synchronization is NOT needed for the + * timer heap. + */ +#define PJ_TIMER_HEAP_NO_SYNCHRONIZE (1) + +/** + * Calculate memory size required to create a timer heap. + * + * @param count Number of timer entries to be supported. + * @return Memory size requirement in bytes. + */ +PJ_DECL(pj_size_t) pj_timer_heap_mem_size(pj_size_t count); + +/** + * Create a timer heap. + * + * @param pool The pool where allocations in the timer heap will be + * allocated. The timer heap will dynamicly allocate + * more storate from the pool if the number of timer + * entries registered is more than the size originally + * requested when calling this function. + * @param count The maximum number of timer entries to be supported + * initially. If the application registers more entries + * during runtime, then the timer heap will resize. + * @param flag Creation flag, currently only PJ_TIMER_HEAP_NO_SYNCHRONIZE + * is recognized.. + * @param ht Pointer to receive the created timer heap. + * + * @return PJ_SUCCESS, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_timer_heap_create( pj_pool_t *pool, + pj_size_t count, + unsigned flag, + pj_timer_heap_t **ht); + +/** + * Initialize a timer entry. Application should call this function at least + * once before scheduling the entry to the timer heap, to properly initialize + * the timer entry. + * + * @param entry The timer entry to be initialized. + * @param id Arbitrary ID assigned by the user/owner of this entry. + * Applications can use this ID to distinguish multiple + * timer entries that share the same callback and user_data. + * @param user_data User data to be associated with this entry. + * Applications normally will put the instance of object that + * owns the timer entry in this field. + * @param cb Callback function to be called when the timer elapses. + * + * @return The timer entry itself. + */ +PJ_DECL(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry, + int id, + void *user_data, + pj_timer_heap_callback *cb ); + +/** + * Schedule a timer entry which will expire AFTER the specified delay. + * + * @param ht The timer heap. + * @param entry The entry to be registered. + * @param delay The interval to expire. + * @return PJ_SUCCESS, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht, + pj_timer_entry *entry, + const pj_time_val *delay); + +/** + * Cancel a previously registered timer. + * + * @param ht The timer heap. + * @param entry The entry to be cancelled. + * @return The number of timer cancelled, which should be one if the + * entry has really been registered, or zero if no timer was + * cancelled. + */ +PJ_DECL(int) pj_timer_heap_cancel( pj_timer_heap_t *ht, + pj_timer_entry *entry); + +/** + * Get the number of timer entries. + * + * @param ht The timer heap. + * @return The number of timer entries. + */ +PJ_DECL(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht ); + +/** + * Get the earliest time registered in the timer heap. The timer heap + * MUST have at least one timer being scheduled (application should use + * #pj_timer_heap_count() before calling this function). + * + * @param ht The timer heap. + * @param timeval The time deadline of the earliest timer entry. + * + * @return PJ_SUCCESS, or PJ_ENOTFOUND if no entry is scheduled. + */ +PJ_DECL(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t *ht, + pj_time_val *timeval); + +/** + * Poll the timer heap, check for expired timers and call the callback for + * each of the expired timers. + * + * @param ht The timer heap. + * @param next_delay If this parameter is not NULL, it will be filled up with + * the time delay until the next timer elapsed, or -1 in + * the sec part if no entry exist. + * @return The number of timers expired. + */ +PJ_DECL(int) pj_timer_heap_poll( pj_timer_heap_t *ht, pj_time_val *next_delay); + +/** + * @} + */ + +PJ_END_DECL + +#endif /* __PJ_TIMER_H__ */ + diff --git a/pjlib/include/pj/types.h b/pjlib/include/pj/types.h index 0ad77d71..352fa391 100644 --- a/pjlib/include/pj/types.h +++ b/pjlib/include/pj/types.h @@ -1,418 +1,418 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/types.h 11 10/14/05 12:26a Bennylp $ */ - -#ifndef __PJ_TYPES_H__ -#define __PJ_TYPES_H__ - - -/** - * @defgroup PJ PJ Library - */ -/** - * @file types.h - * @brief Declaration of basic types and utility. - */ -/** - * @defgroup PJ_BASIC Basic Data Types and Library Functionality. - * @ingroup PJ_DS - * @{ - */ -#include - -PJ_BEGIN_DECL - -/////////////////////////////////////////////////////////////////////////////// - -/** Unsigned 32bit integer. */ -typedef int pj_int32_t; - -/** Signed 32bit integer. */ -typedef unsigned int pj_uint32_t; - -/** Unsigned 16bit integer. */ -typedef short pj_int16_t; - -/** Signed 16bit integer. */ -typedef unsigned short pj_uint16_t; - -/** Unsigned 8bit integer. */ -typedef signed char pj_int8_t; - -/** Signed 16bit integer. */ -typedef unsigned char pj_uint8_t; - -/** Large unsigned integer. */ -typedef size_t pj_size_t; - -/** Large signed integer. */ -typedef long pj_ssize_t; - -/** Status code. */ -typedef int pj_status_t; - -/** Boolean. */ -typedef int pj_bool_t; - -/** Status is OK. */ -#define PJ_SUCCESS 0 - -/** True value. */ -#define PJ_TRUE 1 - -/** False value. */ -#define PJ_FALSE 0 - - -/////////////////////////////////////////////////////////////////////////////// -/* - * Data structure types. - */ -/** - * This type is used as replacement to legacy C string, and used throughout - * the library. By convention, the string is NOT null terminated. - */ -struct pj_str_t -{ - /** Buffer pointer, which is by convention NOT null terminated. */ - char *ptr; - - /** The length of the string. */ - pj_ssize_t slen; -}; - - -/** - * The opaque data type for linked list, which is used as arguments throughout - * the linked list operations. - */ -typedef void pj_list_type; - -/** - * List. - */ -typedef struct pj_list pj_list; - -/** - * Opaque data type for hash tables. - */ -typedef struct pj_hash_table_t pj_hash_table_t; - -/** - * Opaque data type for hash entry (only used internally by hash table). - */ -typedef struct pj_hash_entry pj_hash_entry; - -/** - * Data type for hash search iterator. - * This structure should be opaque, however applications need to declare - * concrete variable of this type, that's why the declaration is visible here. - */ -typedef struct pj_hash_iterator_t -{ - pj_uint32_t index; /**< Internal index. */ - pj_hash_entry *entry; /**< Internal entry. */ -} pj_hash_iterator_t; - - -/** - * Forward declaration for memory pool factory. - */ -typedef struct pj_pool_factory pj_pool_factory; - -/** - * Opaque data type for memory pool. - */ -typedef struct pj_pool_t pj_pool_t; - -/** - * Forward declaration for caching pool, a pool factory implementation. - */ -typedef struct pj_caching_pool pj_caching_pool; - -/** - * This type is used as replacement to legacy C string, and used throughout - * the library. - */ -typedef struct pj_str_t pj_str_t; - -/** - * Opaque data type for I/O Queue structure. - */ -typedef struct pj_ioqueue_t pj_ioqueue_t; - -/** - * Opaque data type for key that identifies a handle registered to the - * I/O queue framework. - */ -typedef struct pj_ioqueue_key_t pj_ioqueue_key_t; - -/** - * Opaque data to identify timer heap. - */ -typedef struct pj_timer_heap_t pj_timer_heap_t; - -/** - * Forward declaration for timer entry. - */ -typedef struct pj_timer_entry pj_timer_entry; - -/** - * Opaque data type for atomic operations. - */ -typedef struct pj_atomic_t pj_atomic_t; - -/** - * Value type of an atomic variable. - */ -typedef PJ_ATOMIC_VALUE_TYPE pj_atomic_value_t; - -/////////////////////////////////////////////////////////////////////////////// - -/** Thread handle. */ -typedef struct pj_thread_t pj_thread_t; - -/** Lock object. */ -typedef struct pj_lock_t pj_lock_t; - -/** Mutex handle. */ -typedef struct pj_mutex_t pj_mutex_t; - -/** Semaphore handle. */ -typedef struct pj_sem_t pj_sem_t; - -/** Event object. */ -typedef struct pj_event_t pj_event_t; - -/** Unidirectional stream pipe object. */ -typedef struct pj_pipe_t pj_pipe_t; - -/** Operating system handle. */ -typedef void *pj_oshandle_t; - -/** Socket handle. */ -typedef long pj_sock_t; - -/** Generic socket address. */ -typedef void pj_sockaddr_t; - -/** Color type. */ -typedef unsigned int pj_color_t; - -/** Exception id. */ -typedef int pj_exception_id_t; - -/////////////////////////////////////////////////////////////////////////////// - -/** Utility macro to compute the number of elements in static array. */ -#define PJ_ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) - -/** Maximum value for signed 32-bit integer. */ -#define PJ_MAXINT32 0x7FFFFFFFL - -/** - * Length of object names. - */ -#define PJ_MAX_OBJ_NAME 16 - -/////////////////////////////////////////////////////////////////////////////// -/* - * General. - */ -/** - * Initialize the PJ Library. - * This function must be called before using the library. The purpose of this - * function is to initialize static library data, such as character table used - * in random string generation, and to initialize operating system dependent - * functionality (such as WSAStartup() in Windows). - */ -PJ_DECL(pj_status_t) pj_init(void); - - -/** - * @} - */ -/** - * @addtogroup PJ_TIME Time Data Type and Manipulation. - * @ingroup PJ_MISC - * @{ - */ - -/** - * Representation of time value in this library. - * This type can be used to represent either an interval or a specific time - * or date. - */ -typedef struct pj_time_val -{ - /** The seconds part of the time. */ - long sec; - - /** The miliseconds fraction of the time. */ - long msec; - -} pj_time_val; - -/** - * Normalize the value in time value. - * @param t Time value to be normalized. - */ -PJ_DECL(void) pj_time_val_normalize(pj_time_val *t); - -/** - * Get the total time value in miliseconds. This is the same as - * multiplying the second part with 1000 and then add the miliseconds - * part to the result. - * - * @param t The time value. - * @return Total time in miliseconds. - * @hideinitializer - */ -#define PJ_TIME_VAL_MSEC(t) ((t).sec * 1000 + (t).msec) - -/** - * This macro will check if \a t1 is equal to \a t2. - * - * @param t1 The first time value to compare. - * @param t2 The second time value to compare. - * @return Non-zero if both time values are equal. - * @hideinitializer - */ -#define PJ_TIME_VAL_EQ(t1, t2) ((t1).sec==(t2).sec && (t1).msec==(t2).msec) - -/** - * This macro will check if \a t1 is greater than \a t2 - * - * @param t1 The first time value to compare. - * @param t2 The second time value to compare. - * @return Non-zero if t1 is greater than t2. - * @hideinitializer - */ -#define PJ_TIME_VAL_GT(t1, t2) ((t1).sec>(t2).sec || \ - ((t1).sec==(t2).sec && (t1).msec>(t2).msec)) - -/** - * This macro will check if \a t1 is greater than or equal to \a t2 - * - * @param t1 The first time value to compare. - * @param t2 The second time value to compare. - * @return Non-zero if t1 is greater than or equal to t2. - * @hideinitializer - */ -#define PJ_TIME_VAL_GTE(t1, t2) (PJ_TIME_VAL_GT(t1,t2) || \ - PJ_TIME_VAL_EQ(t1,t2)) - -/** - * This macro will check if \a t1 is less than \a t2 - * - * @param t1 The first time value to compare. - * @param t2 The second time value to compare. - * @return Non-zero if t1 is less than t2. - * @hideinitializer - */ -#define PJ_TIME_VAL_LT(t1, t2) (!(PJ_TIME_VAL_GTE(t1,t2))) - -/** - * This macro will check if \a t1 is less than or equal to \a t2. - * - * @param t1 The first time value to compare. - * @param t2 The second time value to compare. - * @return Non-zero if t1 is less than or equal to t2. - * @hideinitializer - */ -#define PJ_TIME_VAL_LTE(t1, t2) (!PJ_TIME_VAL_GT(t1, t2)) - -/** - * Add \a t2 to \a t1 and store the result in \a t1. Effectively - * - * this macro will expand as: (\a t1 += \a t2). - * @param t1 The time value to add. - * @param t2 The time value to be added to \a t1. - * @hideinitializer - */ -#define PJ_TIME_VAL_ADD(t1, t2) do { \ - (t1).sec += (t2).sec; \ - (t1).msec += (t2).msec; \ - pj_time_val_normalize(&(t1)); \ - } while (0) - - -/** - * Substract \a t2 from \a t1 and store the result in \a t1. Effectively - * this macro will expand as (\a t1 -= \a t2). - * - * @param t1 The time value to subsctract. - * @param t2 The time value to be substracted from \a t1. - * @hideinitializer - */ -#define PJ_TIME_VAL_SUB(t1, t2) do { \ - (t1).sec -= (t2).sec; \ - (t1).msec -= (t2).msec; \ - pj_time_val_normalize(&(t1)); \ - } while (0) - - -/** - * This structure represent the parsed representation of time. - * It is acquired by calling #pj_time_decode(). - */ -typedef struct pj_parsed_time -{ - /** This represents day of week where value zero means Sunday */ - int wday; - - /** This represents day of the year, 0-365, where zero means - * 1st of January. - */ - int yday; - - /** This represents day of month: 1-31 */ - int day; - - /** This represents month, with the value is 0 - 11 (zero is January) */ - int mon; - - /** This represent the actual year (unlike in ANSI libc where - * the value must be added by 1900). - */ - int year; - - /** This represents the second part, with the value is 0-59 */ - int sec; - - /** This represents the minute part, with the value is: 0-59 */ - int min; - - /** This represents the hour part, with the value is 0-23 */ - int hour; - - /** This represents the milisecond part, with the value is 0-999 */ - int msec; - -} pj_parsed_time; - - -/** - * @} // Time Management - */ - -/////////////////////////////////////////////////////////////////////////////// -/* - * Terminal. - */ -/** - * Color code combination. - */ -enum { - PJ_TERM_COLOR_R = 2, /**< Red */ - PJ_TERM_COLOR_G = 4, /**< Green */ - PJ_TERM_COLOR_B = 1, /**< Blue. */ - PJ_TERM_COLOR_BRIGHT = 8 /**< Bright mask. */ -}; - - - - -PJ_END_DECL - - -#endif /* __PJ_TYPES_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pj/types.h 11 10/14/05 12:26a Bennylp $ */ + +#ifndef __PJ_TYPES_H__ +#define __PJ_TYPES_H__ + + +/** + * @defgroup PJ PJ Library + */ +/** + * @file types.h + * @brief Declaration of basic types and utility. + */ +/** + * @defgroup PJ_BASIC Basic Data Types and Library Functionality. + * @ingroup PJ_DS + * @{ + */ +#include + +PJ_BEGIN_DECL + +/////////////////////////////////////////////////////////////////////////////// + +/** Unsigned 32bit integer. */ +typedef int pj_int32_t; + +/** Signed 32bit integer. */ +typedef unsigned int pj_uint32_t; + +/** Unsigned 16bit integer. */ +typedef short pj_int16_t; + +/** Signed 16bit integer. */ +typedef unsigned short pj_uint16_t; + +/** Unsigned 8bit integer. */ +typedef signed char pj_int8_t; + +/** Signed 16bit integer. */ +typedef unsigned char pj_uint8_t; + +/** Large unsigned integer. */ +typedef size_t pj_size_t; + +/** Large signed integer. */ +typedef long pj_ssize_t; + +/** Status code. */ +typedef int pj_status_t; + +/** Boolean. */ +typedef int pj_bool_t; + +/** Status is OK. */ +#define PJ_SUCCESS 0 + +/** True value. */ +#define PJ_TRUE 1 + +/** False value. */ +#define PJ_FALSE 0 + + +/////////////////////////////////////////////////////////////////////////////// +/* + * Data structure types. + */ +/** + * This type is used as replacement to legacy C string, and used throughout + * the library. By convention, the string is NOT null terminated. + */ +struct pj_str_t +{ + /** Buffer pointer, which is by convention NOT null terminated. */ + char *ptr; + + /** The length of the string. */ + pj_ssize_t slen; +}; + + +/** + * The opaque data type for linked list, which is used as arguments throughout + * the linked list operations. + */ +typedef void pj_list_type; + +/** + * List. + */ +typedef struct pj_list pj_list; + +/** + * Opaque data type for hash tables. + */ +typedef struct pj_hash_table_t pj_hash_table_t; + +/** + * Opaque data type for hash entry (only used internally by hash table). + */ +typedef struct pj_hash_entry pj_hash_entry; + +/** + * Data type for hash search iterator. + * This structure should be opaque, however applications need to declare + * concrete variable of this type, that's why the declaration is visible here. + */ +typedef struct pj_hash_iterator_t +{ + pj_uint32_t index; /**< Internal index. */ + pj_hash_entry *entry; /**< Internal entry. */ +} pj_hash_iterator_t; + + +/** + * Forward declaration for memory pool factory. + */ +typedef struct pj_pool_factory pj_pool_factory; + +/** + * Opaque data type for memory pool. + */ +typedef struct pj_pool_t pj_pool_t; + +/** + * Forward declaration for caching pool, a pool factory implementation. + */ +typedef struct pj_caching_pool pj_caching_pool; + +/** + * This type is used as replacement to legacy C string, and used throughout + * the library. + */ +typedef struct pj_str_t pj_str_t; + +/** + * Opaque data type for I/O Queue structure. + */ +typedef struct pj_ioqueue_t pj_ioqueue_t; + +/** + * Opaque data type for key that identifies a handle registered to the + * I/O queue framework. + */ +typedef struct pj_ioqueue_key_t pj_ioqueue_key_t; + +/** + * Opaque data to identify timer heap. + */ +typedef struct pj_timer_heap_t pj_timer_heap_t; + +/** + * Forward declaration for timer entry. + */ +typedef struct pj_timer_entry pj_timer_entry; + +/** + * Opaque data type for atomic operations. + */ +typedef struct pj_atomic_t pj_atomic_t; + +/** + * Value type of an atomic variable. + */ +typedef PJ_ATOMIC_VALUE_TYPE pj_atomic_value_t; + +/////////////////////////////////////////////////////////////////////////////// + +/** Thread handle. */ +typedef struct pj_thread_t pj_thread_t; + +/** Lock object. */ +typedef struct pj_lock_t pj_lock_t; + +/** Mutex handle. */ +typedef struct pj_mutex_t pj_mutex_t; + +/** Semaphore handle. */ +typedef struct pj_sem_t pj_sem_t; + +/** Event object. */ +typedef struct pj_event_t pj_event_t; + +/** Unidirectional stream pipe object. */ +typedef struct pj_pipe_t pj_pipe_t; + +/** Operating system handle. */ +typedef void *pj_oshandle_t; + +/** Socket handle. */ +typedef long pj_sock_t; + +/** Generic socket address. */ +typedef void pj_sockaddr_t; + +/** Color type. */ +typedef unsigned int pj_color_t; + +/** Exception id. */ +typedef int pj_exception_id_t; + +/////////////////////////////////////////////////////////////////////////////// + +/** Utility macro to compute the number of elements in static array. */ +#define PJ_ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) + +/** Maximum value for signed 32-bit integer. */ +#define PJ_MAXINT32 0x7FFFFFFFL + +/** + * Length of object names. + */ +#define PJ_MAX_OBJ_NAME 16 + +/////////////////////////////////////////////////////////////////////////////// +/* + * General. + */ +/** + * Initialize the PJ Library. + * This function must be called before using the library. The purpose of this + * function is to initialize static library data, such as character table used + * in random string generation, and to initialize operating system dependent + * functionality (such as WSAStartup() in Windows). + */ +PJ_DECL(pj_status_t) pj_init(void); + + +/** + * @} + */ +/** + * @addtogroup PJ_TIME Time Data Type and Manipulation. + * @ingroup PJ_MISC + * @{ + */ + +/** + * Representation of time value in this library. + * This type can be used to represent either an interval or a specific time + * or date. + */ +typedef struct pj_time_val +{ + /** The seconds part of the time. */ + long sec; + + /** The miliseconds fraction of the time. */ + long msec; + +} pj_time_val; + +/** + * Normalize the value in time value. + * @param t Time value to be normalized. + */ +PJ_DECL(void) pj_time_val_normalize(pj_time_val *t); + +/** + * Get the total time value in miliseconds. This is the same as + * multiplying the second part with 1000 and then add the miliseconds + * part to the result. + * + * @param t The time value. + * @return Total time in miliseconds. + * @hideinitializer + */ +#define PJ_TIME_VAL_MSEC(t) ((t).sec * 1000 + (t).msec) + +/** + * This macro will check if \a t1 is equal to \a t2. + * + * @param t1 The first time value to compare. + * @param t2 The second time value to compare. + * @return Non-zero if both time values are equal. + * @hideinitializer + */ +#define PJ_TIME_VAL_EQ(t1, t2) ((t1).sec==(t2).sec && (t1).msec==(t2).msec) + +/** + * This macro will check if \a t1 is greater than \a t2 + * + * @param t1 The first time value to compare. + * @param t2 The second time value to compare. + * @return Non-zero if t1 is greater than t2. + * @hideinitializer + */ +#define PJ_TIME_VAL_GT(t1, t2) ((t1).sec>(t2).sec || \ + ((t1).sec==(t2).sec && (t1).msec>(t2).msec)) + +/** + * This macro will check if \a t1 is greater than or equal to \a t2 + * + * @param t1 The first time value to compare. + * @param t2 The second time value to compare. + * @return Non-zero if t1 is greater than or equal to t2. + * @hideinitializer + */ +#define PJ_TIME_VAL_GTE(t1, t2) (PJ_TIME_VAL_GT(t1,t2) || \ + PJ_TIME_VAL_EQ(t1,t2)) + +/** + * This macro will check if \a t1 is less than \a t2 + * + * @param t1 The first time value to compare. + * @param t2 The second time value to compare. + * @return Non-zero if t1 is less than t2. + * @hideinitializer + */ +#define PJ_TIME_VAL_LT(t1, t2) (!(PJ_TIME_VAL_GTE(t1,t2))) + +/** + * This macro will check if \a t1 is less than or equal to \a t2. + * + * @param t1 The first time value to compare. + * @param t2 The second time value to compare. + * @return Non-zero if t1 is less than or equal to t2. + * @hideinitializer + */ +#define PJ_TIME_VAL_LTE(t1, t2) (!PJ_TIME_VAL_GT(t1, t2)) + +/** + * Add \a t2 to \a t1 and store the result in \a t1. Effectively + * + * this macro will expand as: (\a t1 += \a t2). + * @param t1 The time value to add. + * @param t2 The time value to be added to \a t1. + * @hideinitializer + */ +#define PJ_TIME_VAL_ADD(t1, t2) do { \ + (t1).sec += (t2).sec; \ + (t1).msec += (t2).msec; \ + pj_time_val_normalize(&(t1)); \ + } while (0) + + +/** + * Substract \a t2 from \a t1 and store the result in \a t1. Effectively + * this macro will expand as (\a t1 -= \a t2). + * + * @param t1 The time value to subsctract. + * @param t2 The time value to be substracted from \a t1. + * @hideinitializer + */ +#define PJ_TIME_VAL_SUB(t1, t2) do { \ + (t1).sec -= (t2).sec; \ + (t1).msec -= (t2).msec; \ + pj_time_val_normalize(&(t1)); \ + } while (0) + + +/** + * This structure represent the parsed representation of time. + * It is acquired by calling #pj_time_decode(). + */ +typedef struct pj_parsed_time +{ + /** This represents day of week where value zero means Sunday */ + int wday; + + /** This represents day of the year, 0-365, where zero means + * 1st of January. + */ + int yday; + + /** This represents day of month: 1-31 */ + int day; + + /** This represents month, with the value is 0 - 11 (zero is January) */ + int mon; + + /** This represent the actual year (unlike in ANSI libc where + * the value must be added by 1900). + */ + int year; + + /** This represents the second part, with the value is 0-59 */ + int sec; + + /** This represents the minute part, with the value is: 0-59 */ + int min; + + /** This represents the hour part, with the value is 0-23 */ + int hour; + + /** This represents the milisecond part, with the value is 0-999 */ + int msec; + +} pj_parsed_time; + + +/** + * @} // Time Management + */ + +/////////////////////////////////////////////////////////////////////////////// +/* + * Terminal. + */ +/** + * Color code combination. + */ +enum { + PJ_TERM_COLOR_R = 2, /**< Red */ + PJ_TERM_COLOR_G = 4, /**< Green */ + PJ_TERM_COLOR_B = 1, /**< Blue. */ + PJ_TERM_COLOR_BRIGHT = 8 /**< Bright mask. */ +}; + + + + +PJ_END_DECL + + +#endif /* __PJ_TYPES_H__ */ + diff --git a/pjlib/include/pj/xml.h b/pjlib/include/pj/xml.h index 6311448e..a202b28d 100644 --- a/pjlib/include/pj/xml.h +++ b/pjlib/include/pj/xml.h @@ -1,155 +1,155 @@ -/* $Header: /pjproject-0.3/pjlib/include/pj/xml.h 4 10/14/05 12:26a Bennylp $ */ - -#ifndef __PJ_XML_H__ -#define __PJ_XML_H__ - -/** - * @file xml.h - * @brief PJLIB XML Parser/Helper. - */ - -#include -#include - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_XML XML Parser/Helper. - * @ingroup PJ - * @{ - */ - -/** Typedef for XML attribute. */ -typedef struct pj_xml_attr pj_xml_attr; - -/** Typedef for XML nodes. */ -typedef struct pj_xml_node pj_xml_node; - -/** This structure declares XML attribute. */ -struct pj_xml_attr -{ - PJ_DECL_LIST_MEMBER(pj_xml_attr) - pj_str_t name; /**< Attribute name. */ - pj_str_t value; /**< Attribute value. */ -}; - -/** This structure describes XML node head inside XML node structure. - */ -typedef struct pj_xml_node_head -{ - PJ_DECL_LIST_MEMBER(pj_xml_node) -} pj_xml_node_head; - -/** This structure describes XML node. */ -struct pj_xml_node -{ - PJ_DECL_LIST_MEMBER(pj_xml_node) /** List @a prev and @a next member */ - pj_str_t name; /** Node name. */ - pj_xml_attr attr_head; /** Attribute list. */ - pj_xml_node_head node_head; /** Node list. */ - pj_str_t content; /** Node content. */ -}; - -/** - * Parse XML message into XML document with a single root node. The parser - * is capable of parsing XML processing instruction construct (" +#include + +PJ_BEGIN_DECL + +/** + * @defgroup PJ_XML XML Parser/Helper. + * @ingroup PJ + * @{ + */ + +/** Typedef for XML attribute. */ +typedef struct pj_xml_attr pj_xml_attr; + +/** Typedef for XML nodes. */ +typedef struct pj_xml_node pj_xml_node; + +/** This structure declares XML attribute. */ +struct pj_xml_attr +{ + PJ_DECL_LIST_MEMBER(pj_xml_attr) + pj_str_t name; /**< Attribute name. */ + pj_str_t value; /**< Attribute value. */ +}; + +/** This structure describes XML node head inside XML node structure. + */ +typedef struct pj_xml_node_head +{ + PJ_DECL_LIST_MEMBER(pj_xml_node) +} pj_xml_node_head; + +/** This structure describes XML node. */ +struct pj_xml_node +{ + PJ_DECL_LIST_MEMBER(pj_xml_node) /** List @a prev and @a next member */ + pj_str_t name; /** Node name. */ + pj_xml_attr attr_head; /** Attribute list. */ + pj_xml_node_head node_head; /** Node list. */ + pj_str_t content; /** Node content. */ +}; + +/** + * Parse XML message into XML document with a single root node. The parser + * is capable of parsing XML processing instruction construct (" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#endif /* __PJLIB_H__ */ - +/* $Header: /pjproject-0.3/pjlib/include/pjlib.h 6 10/29/05 11:30a Bennylp $ */ +#ifndef __PJLIB_H__ +#define __PJLIB_H__ + +/** + * @file pjlib.h + * @brief Include all PJLIB header files. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#endif /* __PJLIB_H__ */ + diff --git a/pjlib/src/pj/addr_resolv_linux_kernel.c b/pjlib/src/pj/addr_resolv_linux_kernel.c index 7c085c60..c49be1c2 100644 --- a/pjlib/src/pj/addr_resolv_linux_kernel.c +++ b/pjlib/src/pj/addr_resolv_linux_kernel.c @@ -1,14 +1,14 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/addr_resolv_linux_kernel.c 1 10/05/05 4:41p Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/addr_resolv_linux_kernel.c $ - * - * 1 10/05/05 4:41p Bennylp - * Created. - * - */ -#include - -PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *hostname, pj_hostent *phe) -{ - return -1; -} - +/* $Header: /pjproject-0.3/pjlib/src/pj/addr_resolv_linux_kernel.c 1 10/05/05 4:41p Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/addr_resolv_linux_kernel.c $ + * + * 1 10/05/05 4:41p Bennylp + * Created. + * + */ +#include + +PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *hostname, pj_hostent *phe) +{ + return -1; +} + diff --git a/pjlib/src/pj/addr_resolv_sock.c b/pjlib/src/pj/addr_resolv_sock.c index 0200c65a..deb0a6e9 100644 --- a/pjlib/src/pj/addr_resolv_sock.c +++ b/pjlib/src/pj/addr_resolv_sock.c @@ -1,44 +1,44 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/addr_resolv_sock.c 2 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/addr_resolv_sock.c $ - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 9/22/05 10:38a Bennylp - * Created. - * - */ -#include -#include -#include -#include -#include - - -PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *hostname, pj_hostent *phe) -{ - struct hostent *he; - char copy[PJ_MAX_HOSTNAME]; - - pj_assert(hostname && hostname ->slen < PJ_MAX_HOSTNAME); - - if (hostname->slen >= PJ_MAX_HOSTNAME) - return PJ_ENAMETOOLONG; - - pj_memcpy(copy, hostname->ptr, hostname->slen); - copy[ hostname->slen ] = '\0'; - - he = gethostbyname(copy); - if (!he) - return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); - - phe->h_name = he->h_name; - phe->h_aliases = he->h_aliases; - phe->h_addrtype = he->h_addrtype; - phe->h_length = he->h_length; - phe->h_addr_list = he->h_addr_list; - - return PJ_SUCCESS; -} - +/* $Header: /pjproject-0.3/pjlib/src/pj/addr_resolv_sock.c 2 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/addr_resolv_sock.c $ + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 9/22/05 10:38a Bennylp + * Created. + * + */ +#include +#include +#include +#include +#include + + +PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *hostname, pj_hostent *phe) +{ + struct hostent *he; + char copy[PJ_MAX_HOSTNAME]; + + pj_assert(hostname && hostname ->slen < PJ_MAX_HOSTNAME); + + if (hostname->slen >= PJ_MAX_HOSTNAME) + return PJ_ENAMETOOLONG; + + pj_memcpy(copy, hostname->ptr, hostname->slen); + copy[ hostname->slen ] = '\0'; + + he = gethostbyname(copy); + if (!he) + return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); + + phe->h_name = he->h_name; + phe->h_aliases = he->h_aliases; + phe->h_addrtype = he->h_addrtype; + phe->h_length = he->h_length; + phe->h_addr_list = he->h_addr_list; + + return PJ_SUCCESS; +} + diff --git a/pjlib/src/pj/array.c b/pjlib/src/pj/array.c index edb4994d..06a3ad1a 100644 --- a/pjlib/src/pj/array.c +++ b/pjlib/src/pj/array.c @@ -1,63 +1,63 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/array.c 5 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/array.c $ - * - * 5 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 4 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include -#include - -PJ_DEF(void) pj_array_insert( void *array, - unsigned elem_size, - unsigned count, - unsigned pos, - const void *value) -{ - if (count && pos < count-1) { - pj_memmove( (char*)array + (pos+1)*elem_size, - (char*)array + pos*elem_size, - (count-pos)*elem_size); - } - pj_memmove((char*)array + pos*elem_size, value, elem_size); -} - -PJ_DEF(void) pj_array_erase( void *array, - unsigned elem_size, - unsigned count, - unsigned pos) -{ - pj_assert(count != 0); - if (pos < count-1) { - pj_memmove( (char*)array + pos*elem_size, - (char*)array + (pos+1)*elem_size, - (count-pos-1)*elem_size); - } -} - -PJ_DEF(pj_status_t) pj_array_find( const void *array, - unsigned elem_size, - unsigned count, - pj_status_t (*matching)(const void *value), - void **result) -{ - unsigned i; - const char *char_array = array; - for (i=0; i +#include +#include +#include + +PJ_DEF(void) pj_array_insert( void *array, + unsigned elem_size, + unsigned count, + unsigned pos, + const void *value) +{ + if (count && pos < count-1) { + pj_memmove( (char*)array + (pos+1)*elem_size, + (char*)array + pos*elem_size, + (count-pos)*elem_size); + } + pj_memmove((char*)array + pos*elem_size, value, elem_size); +} + +PJ_DEF(void) pj_array_erase( void *array, + unsigned elem_size, + unsigned count, + unsigned pos) +{ + pj_assert(count != 0); + if (pos < count-1) { + pj_memmove( (char*)array + pos*elem_size, + (char*)array + (pos+1)*elem_size, + (count-pos-1)*elem_size); + } +} + +PJ_DEF(pj_status_t) pj_array_find( const void *array, + unsigned elem_size, + unsigned count, + pj_status_t (*matching)(const void *value), + void **result) +{ + unsigned i; + const char *char_array = array; + for (i=0; i - -.global __longjmp -.type __longjmp,%function -.align 4 -__longjmp: - movl 4(%esp), %ecx /* User's jmp_buf in %ecx. */ - movl 8(%esp), %eax /* Second argument is return value. */ - /* Save the return address now. */ - movl (JB_PC*4)(%ecx), %edx - /* Restore registers. */ - movl (JB_BX*4)(%ecx), %ebx - movl (JB_SI*4)(%ecx), %esi - movl (JB_DI*4)(%ecx), %edi - movl (JB_BP*4)(%ecx), %ebp - movl (JB_SP*4)(%ecx), %esp - /* Jump to saved PC. */ - jmp *%edx -.size __longjmp,.-__longjmp - +/* longjmp for i386. + Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#define _ASM +#define _SETJMP_H +#define PJ_LINUX_KERNEL 1 +#include + +.global __longjmp +.type __longjmp,%function +.align 4 +__longjmp: + movl 4(%esp), %ecx /* User's jmp_buf in %ecx. */ + movl 8(%esp), %eax /* Second argument is return value. */ + /* Save the return address now. */ + movl (JB_PC*4)(%ecx), %edx + /* Restore registers. */ + movl (JB_BX*4)(%ecx), %ebx + movl (JB_SI*4)(%ecx), %esi + movl (JB_DI*4)(%ecx), %edi + movl (JB_BP*4)(%ecx), %ebp + movl (JB_SP*4)(%ecx), %esp + /* Jump to saved PC. */ + jmp *%edx +.size __longjmp,.-__longjmp + diff --git a/pjlib/src/pj/compat/setjmp_i386.S b/pjlib/src/pj/compat/setjmp_i386.S index 6810c554..9cdaaff7 100644 --- a/pjlib/src/pj/compat/setjmp_i386.S +++ b/pjlib/src/pj/compat/setjmp_i386.S @@ -1,61 +1,61 @@ -/* setjmp for i386, ELF version. - Copyright (C) 1995, 1996, 1997, 2000, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#define _ASM -#define _SETJMP_H -#define PJ_LINUX_KERNEL 1 -#include - - -.global __sigsetjmp -.type __sigsetjmp,%function -.align 4 - -__sigsetjmp: - movl 4 (%esp), %eax - /* Save registers. */ - movl %ebx, (0 *4)(%eax) - movl %esi, (1 *4)(%eax) - movl %edi, (2 *4)(%eax) - /* Save SP as it will be after we return. */ - leal 4(%esp), %ecx - movl %ecx, (4 *4)(%eax) - /* Save PC we are returning to now. */ - movl 0(%esp), %ecx - movl %ecx, (5 *4)(%eax) - /* Save caller's frame pointer. */ - movl %ebp, (3 *4)(%eax) - - /* Make a tail call to __sigjmp_save; it takes the same args. */ -#ifdef __PIC__ - /* We cannot use the PLT, because it requires that %ebx be set, but - we can't save and restore our caller's value. Instead, we do an - indirect jump through the GOT, using for the temporary register - %ecx, which is call-clobbered. */ - call .Lhere -.Lhere: - popl %ecx - addl $_GLOBAL_OFFSET_TABLE_+[.- .Lhere ], %ecx - movl __sigjmp_save @GOT (%ecx), %ecx - jmp *%ecx -#else - jmp __sigjmp_save -#endif -.size __sigsetjmp,.-__sigsetjmp - +/* setjmp for i386, ELF version. + Copyright (C) 1995, 1996, 1997, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#define _ASM +#define _SETJMP_H +#define PJ_LINUX_KERNEL 1 +#include + + +.global __sigsetjmp +.type __sigsetjmp,%function +.align 4 + +__sigsetjmp: + movl 4 (%esp), %eax + /* Save registers. */ + movl %ebx, (0 *4)(%eax) + movl %esi, (1 *4)(%eax) + movl %edi, (2 *4)(%eax) + /* Save SP as it will be after we return. */ + leal 4(%esp), %ecx + movl %ecx, (4 *4)(%eax) + /* Save PC we are returning to now. */ + movl 0(%esp), %ecx + movl %ecx, (5 *4)(%eax) + /* Save caller's frame pointer. */ + movl %ebp, (3 *4)(%eax) + + /* Make a tail call to __sigjmp_save; it takes the same args. */ +#ifdef __PIC__ + /* We cannot use the PLT, because it requires that %ebx be set, but + we can't save and restore our caller's value. Instead, we do an + indirect jump through the GOT, using for the temporary register + %ecx, which is call-clobbered. */ + call .Lhere +.Lhere: + popl %ecx + addl $_GLOBAL_OFFSET_TABLE_+[.- .Lhere ], %ecx + movl __sigjmp_save @GOT (%ecx), %ecx + jmp *%ecx +#else + jmp __sigjmp_save +#endif +.size __sigsetjmp,.-__sigsetjmp + diff --git a/pjlib/src/pj/compat/sigjmp.c b/pjlib/src/pj/compat/sigjmp.c index ead0e363..4abcddfb 100644 --- a/pjlib/src/pj/compat/sigjmp.c +++ b/pjlib/src/pj/compat/sigjmp.c @@ -1,21 +1,21 @@ -#include -#include - -int __sigjmp_save(sigjmp_buf env, int savemask) -{ - return 0; -} - -extern int __sigsetjmp(pj_jmp_buf env, int savemask); -extern void __longjmp(pj_jmp_buf env, int val) __attribute__((noreturn)); - -PJ_DEF(int) pj_setjmp(pj_jmp_buf env) -{ - return __sigsetjmp(env, 0); -} - -PJ_DEF(void) pj_longjmp(pj_jmp_buf env, int val) -{ - __longjmp(env, val); -} - +#include +#include + +int __sigjmp_save(sigjmp_buf env, int savemask) +{ + return 0; +} + +extern int __sigsetjmp(pj_jmp_buf env, int savemask); +extern void __longjmp(pj_jmp_buf env, int val) __attribute__((noreturn)); + +PJ_DEF(int) pj_setjmp(pj_jmp_buf env) +{ + return __sigsetjmp(env, 0); +} + +PJ_DEF(void) pj_longjmp(pj_jmp_buf env, int val) +{ + __longjmp(env, val); +} + diff --git a/pjlib/src/pj/compat/string.c b/pjlib/src/pj/compat/string.c index 25fd11c9..ccaf09a2 100644 --- a/pjlib/src/pj/compat/string.c +++ b/pjlib/src/pj/compat/string.c @@ -1,33 +1,33 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/compat/string.c 1 9/22/05 10:43a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/compat/string.c $ - * - * 1 9/22/05 10:43a Bennylp - * Created. - * - */ -#include -#include -#include - -PJ_DEF(int) strcasecmp(const char *s1, const char *s2) -{ - while ((*s1==*s2) || (pj_tolower(*s1)==pj_tolower(*s2))) { - if (!*s1++) - return 0; - ++s2; - } - return (pj_tolower(*s1) < pj_tolower(*s2)) ? -1 : 1; -} - -PJ_DEF(int) strncasecmp(const char *s1, const char *s2, int len) -{ - if (!len) return 0; - - while ((*s1==*s2) || (pj_tolower(*s1)==pj_tolower(*s2))) { - if (!*s1++ || --len <= 0) - return 0; - ++s2; - } - return (pj_tolower(*s1) < pj_tolower(*s2)) ? -1 : 1; -} - +/* $Header: /pjproject-0.3/pjlib/src/pj/compat/string.c 1 9/22/05 10:43a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/compat/string.c $ + * + * 1 9/22/05 10:43a Bennylp + * Created. + * + */ +#include +#include +#include + +PJ_DEF(int) strcasecmp(const char *s1, const char *s2) +{ + while ((*s1==*s2) || (pj_tolower(*s1)==pj_tolower(*s2))) { + if (!*s1++) + return 0; + ++s2; + } + return (pj_tolower(*s1) < pj_tolower(*s2)) ? -1 : 1; +} + +PJ_DEF(int) strncasecmp(const char *s1, const char *s2, int len) +{ + if (!len) return 0; + + while ((*s1==*s2) || (pj_tolower(*s1)==pj_tolower(*s2))) { + if (!*s1++ || --len <= 0) + return 0; + ++s2; + } + return (pj_tolower(*s1) < pj_tolower(*s2)) ? -1 : 1; +} + diff --git a/pjlib/src/pj/config.c b/pjlib/src/pj/config.c index 5a08c8dd..55d9e339 100644 --- a/pjlib/src/pj/config.c +++ b/pjlib/src/pj/config.c @@ -1,40 +1,40 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/config.c 7 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/config.c $ - * - * 7 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 6 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 5 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include - -static const char *id = "config.c"; -const char *PJ_VERSION = "0.3.0-pre1"; - -PJ_DEF(void) pj_dump_config(void) -{ - PJ_LOG(3, (id, "PJLIB (c)2005 Benny Prijono")); - PJ_LOG(3, (id, "Dumping configurations:")); - PJ_LOG(3, (id, " PJ_VERSION : %s", PJ_VERSION)); - PJ_LOG(3, (id, " PJ_DEBUG : %d", PJ_DEBUG)); - PJ_LOG(3, (id, " PJ_FUNCTIONS_ARE_INLINED : %d", PJ_FUNCTIONS_ARE_INLINED)); - PJ_LOG(3, (id, " PJ_POOL_DEBUG : %d", PJ_POOL_DEBUG)); - PJ_LOG(3, (id, " PJ_HAS_THREADS : %d", PJ_HAS_THREADS)); - PJ_LOG(3, (id, " PJ_LOG_MAX_LEVEL : %d", PJ_LOG_MAX_LEVEL)); - PJ_LOG(3, (id, " PJ_LOG_MAX_SIZE : %d", PJ_LOG_MAX_SIZE)); - PJ_LOG(3, (id, " PJ_LOG_USE_STACK_BUFFER : %d", PJ_LOG_USE_STACK_BUFFER)); - PJ_LOG(3, (id, " PJ_HAS_TCP : %d", PJ_HAS_TCP)); - PJ_LOG(3, (id, " PJ_MAX_HOSTNAME : %d", PJ_MAX_HOSTNAME)); - PJ_LOG(3, (id, " PJ_HAS_SEMAPHORE : %d", PJ_HAS_SEMAPHORE)); - PJ_LOG(3, (id, " PJ_HAS_EVENT_OBJ : %d", PJ_HAS_EVENT_OBJ)); - PJ_LOG(3, (id, " PJ_HAS_HIGH_RES_TIMER : %d", PJ_HAS_HIGH_RES_TIMER)); - PJ_LOG(3, (id, " PJ_(endianness) : %s", (PJ_IS_BIG_ENDIAN?"big-endian":"little-endian"))); - PJ_LOG(3, (id, " PJ_IOQUEUE_MAX_HANDLES : %d", PJ_IOQUEUE_MAX_HANDLES)); -} +/* $Header: /pjproject-0.3/pjlib/src/pj/config.c 7 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/config.c $ + * + * 7 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 6 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 5 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include + +static const char *id = "config.c"; +const char *PJ_VERSION = "0.3.0-pre1"; + +PJ_DEF(void) pj_dump_config(void) +{ + PJ_LOG(3, (id, "PJLIB (c)2005 Benny Prijono")); + PJ_LOG(3, (id, "Dumping configurations:")); + PJ_LOG(3, (id, " PJ_VERSION : %s", PJ_VERSION)); + PJ_LOG(3, (id, " PJ_DEBUG : %d", PJ_DEBUG)); + PJ_LOG(3, (id, " PJ_FUNCTIONS_ARE_INLINED : %d", PJ_FUNCTIONS_ARE_INLINED)); + PJ_LOG(3, (id, " PJ_POOL_DEBUG : %d", PJ_POOL_DEBUG)); + PJ_LOG(3, (id, " PJ_HAS_THREADS : %d", PJ_HAS_THREADS)); + PJ_LOG(3, (id, " PJ_LOG_MAX_LEVEL : %d", PJ_LOG_MAX_LEVEL)); + PJ_LOG(3, (id, " PJ_LOG_MAX_SIZE : %d", PJ_LOG_MAX_SIZE)); + PJ_LOG(3, (id, " PJ_LOG_USE_STACK_BUFFER : %d", PJ_LOG_USE_STACK_BUFFER)); + PJ_LOG(3, (id, " PJ_HAS_TCP : %d", PJ_HAS_TCP)); + PJ_LOG(3, (id, " PJ_MAX_HOSTNAME : %d", PJ_MAX_HOSTNAME)); + PJ_LOG(3, (id, " PJ_HAS_SEMAPHORE : %d", PJ_HAS_SEMAPHORE)); + PJ_LOG(3, (id, " PJ_HAS_EVENT_OBJ : %d", PJ_HAS_EVENT_OBJ)); + PJ_LOG(3, (id, " PJ_HAS_HIGH_RES_TIMER : %d", PJ_HAS_HIGH_RES_TIMER)); + PJ_LOG(3, (id, " PJ_(endianness) : %s", (PJ_IS_BIG_ENDIAN?"big-endian":"little-endian"))); + PJ_LOG(3, (id, " PJ_IOQUEUE_MAX_HANDLES : %d", PJ_IOQUEUE_MAX_HANDLES)); +} diff --git a/pjlib/src/pj/equeue_winnt.c b/pjlib/src/pj/equeue_winnt.c index b1ed4508..ede47d10 100644 --- a/pjlib/src/pj/equeue_winnt.c +++ b/pjlib/src/pj/equeue_winnt.c @@ -1,13 +1,13 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/equeue_winnt.c 2 10/14/05 12:26a Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pj/equeue_winnt.c $ - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 10/05/05 6:19p Bennylp - * Created. - * - */ -#include +/* $Header: /pjproject-0.3/pjlib/src/pj/equeue_winnt.c 2 10/14/05 12:26a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pj/equeue_winnt.c $ + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 10/05/05 6:19p Bennylp + * Created. + * + */ +#include diff --git a/pjlib/src/pj/errno.c b/pjlib/src/pj/errno.c index 218c789f..42979c08 100644 --- a/pjlib/src/pj/errno.c +++ b/pjlib/src/pj/errno.c @@ -1,107 +1,107 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/errno.c 2 10/14/05 12:26a Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pj/errno.c $ - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 10/08/05 9:53a Bennylp - * Created. - * - */ -#include -#include -#include - -/* Prototype for platform specific error message, which will be defined - * in separate file. - */ -extern int platform_strerror( pj_os_err_type code, - char *buf, pj_size_t bufsize ); - -/* PJLIB's own error codes/messages */ -static const struct -{ - int code; - const char *msg; -} err_str[] = -{ - { PJ_EUNKNOWN, "Unknown Error" }, - { PJ_EPENDING, "Pending operation" }, - { PJ_ETOOMANYCONN, "Too many connecting sockets" }, - { PJ_EINVAL, "Invalid value or argument" }, - { PJ_ENAMETOOLONG, "Name too long" }, - { PJ_ENOTFOUND, "Not found" }, - { PJ_ENOMEM, "Not enough memory" }, - { PJ_EBUG, "BUG DETECTED!" }, - { PJ_ETIMEDOUT, "Operation timed out" }, - { PJ_ETOOMANY, "Too many objects of the specified type"}, - { PJ_EBUSY, "Object is busy"}, - { PJ_ENOTSUP, "Option/operation is not supported"}, - { PJ_EINVALIDOP, "Invalid operation"} -}; - -/* - * pjlib_error() - * - * Retrieve message string for PJLIB's own error code. - */ -static int pjlib_error(pj_status_t code, char *buf, pj_size_t size) -{ - unsigned i; - - for (i=0; i= size) len = size-1; - pj_memcpy(buf, err_str[i].msg, len); - buf[len] = '\0'; - return len; - } - } - - *buf++ = '?'; - *buf++ = '?'; - *buf++ = '?'; - *buf++ = '\0'; - return 3; -} - -/* - * pj_strerror() - */ -PJ_DEF(pj_str_t) pj_strerror( pj_status_t statcode, - char *buf, pj_size_t bufsize ) -{ - int len = -1; - pj_str_t errstr; - - if (statcode < PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) { - len = pj_snprintf( buf, bufsize, "Unknown error %d", statcode); - - } else if (statcode < PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE) { - len = pjlib_error(statcode, buf, bufsize); - - } else if (statcode < PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE) { - len = platform_strerror(PJ_STATUS_TO_OS(statcode), buf, bufsize); - - } else if (statcode < PJ_ERRNO_START_USER + PJ_ERRNO_SPACE_SIZE) { - len = pj_snprintf( buf, bufsize, "User error %d", statcode); - - } else { - len = pj_snprintf( buf, bufsize, "Invalid error %d", statcode); - - } - - if (len < 1) { - *buf = '\0'; - len = 0; - } - - errstr.ptr = buf; - errstr.slen = len; - - return errstr; -} - +/* $Header: /pjproject-0.3/pjlib/src/pj/errno.c 2 10/14/05 12:26a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pj/errno.c $ + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 10/08/05 9:53a Bennylp + * Created. + * + */ +#include +#include +#include + +/* Prototype for platform specific error message, which will be defined + * in separate file. + */ +extern int platform_strerror( pj_os_err_type code, + char *buf, pj_size_t bufsize ); + +/* PJLIB's own error codes/messages */ +static const struct +{ + int code; + const char *msg; +} err_str[] = +{ + { PJ_EUNKNOWN, "Unknown Error" }, + { PJ_EPENDING, "Pending operation" }, + { PJ_ETOOMANYCONN, "Too many connecting sockets" }, + { PJ_EINVAL, "Invalid value or argument" }, + { PJ_ENAMETOOLONG, "Name too long" }, + { PJ_ENOTFOUND, "Not found" }, + { PJ_ENOMEM, "Not enough memory" }, + { PJ_EBUG, "BUG DETECTED!" }, + { PJ_ETIMEDOUT, "Operation timed out" }, + { PJ_ETOOMANY, "Too many objects of the specified type"}, + { PJ_EBUSY, "Object is busy"}, + { PJ_ENOTSUP, "Option/operation is not supported"}, + { PJ_EINVALIDOP, "Invalid operation"} +}; + +/* + * pjlib_error() + * + * Retrieve message string for PJLIB's own error code. + */ +static int pjlib_error(pj_status_t code, char *buf, pj_size_t size) +{ + unsigned i; + + for (i=0; i= size) len = size-1; + pj_memcpy(buf, err_str[i].msg, len); + buf[len] = '\0'; + return len; + } + } + + *buf++ = '?'; + *buf++ = '?'; + *buf++ = '?'; + *buf++ = '\0'; + return 3; +} + +/* + * pj_strerror() + */ +PJ_DEF(pj_str_t) pj_strerror( pj_status_t statcode, + char *buf, pj_size_t bufsize ) +{ + int len = -1; + pj_str_t errstr; + + if (statcode < PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) { + len = pj_snprintf( buf, bufsize, "Unknown error %d", statcode); + + } else if (statcode < PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE) { + len = pjlib_error(statcode, buf, bufsize); + + } else if (statcode < PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE) { + len = platform_strerror(PJ_STATUS_TO_OS(statcode), buf, bufsize); + + } else if (statcode < PJ_ERRNO_START_USER + PJ_ERRNO_SPACE_SIZE) { + len = pj_snprintf( buf, bufsize, "User error %d", statcode); + + } else { + len = pj_snprintf( buf, bufsize, "Invalid error %d", statcode); + + } + + if (len < 1) { + *buf = '\0'; + len = 0; + } + + errstr.ptr = buf; + errstr.slen = len; + + return errstr; +} + diff --git a/pjlib/src/pj/except.c b/pjlib/src/pj/except.c index 0525caee..f64ebe82 100644 --- a/pjlib/src/pj/except.c +++ b/pjlib/src/pj/except.c @@ -1,148 +1,148 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/except.c 6 10/14/05 12:26a Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pj/except.c $ - * - * 6 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 5 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 4 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include -#include -#include - -static long thread_local_id = -1; - -#if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0 - static const char *exception_id_names[PJ_MAX_EXCEPTION_ID]; -#else - /* - * Start from 1 (not 0)!!! - * Exception 0 is reserved for normal path of setjmp()!!! - */ - static int last_exception_id = 1; -#endif /* PJ_HAS_EXCEPTION_NAMES */ - - -PJ_DEF(void) pj_throw_exception_(int exception_id) -{ - struct pj_exception_state_t *handler; - - handler = pj_thread_local_get(thread_local_id); - if (handler == NULL) { - PJ_LOG(1,("except.c", "!!!FATAL: unhandled exception %d!\n", exception_id)); - pj_assert(handler != NULL); - /* This will crash the system! */ - } - pj_longjmp(handler->state, exception_id); -} - -PJ_DEF(void) pj_push_exception_handler_(struct pj_exception_state_t *rec) -{ - struct pj_exception_state_t *parent_handler = NULL; - - if (thread_local_id == -1) { - pj_thread_local_alloc(&thread_local_id); - pj_assert(thread_local_id != -1); - } - parent_handler = pj_thread_local_get(thread_local_id); - rec->prev = parent_handler; - pj_thread_local_set(thread_local_id, rec); -} - -PJ_DEF(void) pj_pop_exception_handler_(void) -{ - struct pj_exception_state_t *handler; - - handler = pj_thread_local_get(thread_local_id); - pj_assert(handler != NULL); - pj_thread_local_set(thread_local_id, handler->prev); -} - -#if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0 -PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name, - pj_exception_id_t *id) -{ - unsigned i; - - pj_enter_critical_section(); - - /* - * Start from 1 (not 0)!!! - * Exception 0 is reserved for normal path of setjmp()!!! - */ - for (i=1; i0 && id0 && id"); - - if (exception_id_names[id] == NULL) - return ""; - - return exception_id_names[id]; -} - -#else /* PJ_HAS_EXCEPTION_NAMES */ -PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name, - pj_exception_id_t *id) -{ - PJ_ASSERT_RETURN(last_exception_id < PJ_MAX_EXCEPTION_ID-1, PJ_ETOOMANY); - - *id = last_exception_id++ - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_exception_id_free( pj_exception_id_t id ) -{ - return PJ_SUCCESS; -} - -PJ_DEF(const char*) pj_exception_id_name(pj_exception_id_t id) -{ - return ""; -} - -#endif /* PJ_HAS_EXCEPTION_NAMES */ - - - +/* $Header: /pjproject-0.3/pjlib/src/pj/except.c 6 10/14/05 12:26a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pj/except.c $ + * + * 6 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 5 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 4 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include +#include +#include +#include + +static long thread_local_id = -1; + +#if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0 + static const char *exception_id_names[PJ_MAX_EXCEPTION_ID]; +#else + /* + * Start from 1 (not 0)!!! + * Exception 0 is reserved for normal path of setjmp()!!! + */ + static int last_exception_id = 1; +#endif /* PJ_HAS_EXCEPTION_NAMES */ + + +PJ_DEF(void) pj_throw_exception_(int exception_id) +{ + struct pj_exception_state_t *handler; + + handler = pj_thread_local_get(thread_local_id); + if (handler == NULL) { + PJ_LOG(1,("except.c", "!!!FATAL: unhandled exception %d!\n", exception_id)); + pj_assert(handler != NULL); + /* This will crash the system! */ + } + pj_longjmp(handler->state, exception_id); +} + +PJ_DEF(void) pj_push_exception_handler_(struct pj_exception_state_t *rec) +{ + struct pj_exception_state_t *parent_handler = NULL; + + if (thread_local_id == -1) { + pj_thread_local_alloc(&thread_local_id); + pj_assert(thread_local_id != -1); + } + parent_handler = pj_thread_local_get(thread_local_id); + rec->prev = parent_handler; + pj_thread_local_set(thread_local_id, rec); +} + +PJ_DEF(void) pj_pop_exception_handler_(void) +{ + struct pj_exception_state_t *handler; + + handler = pj_thread_local_get(thread_local_id); + pj_assert(handler != NULL); + pj_thread_local_set(thread_local_id, handler->prev); +} + +#if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0 +PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name, + pj_exception_id_t *id) +{ + unsigned i; + + pj_enter_critical_section(); + + /* + * Start from 1 (not 0)!!! + * Exception 0 is reserved for normal path of setjmp()!!! + */ + for (i=1; i0 && id0 && id"); + + if (exception_id_names[id] == NULL) + return ""; + + return exception_id_names[id]; +} + +#else /* PJ_HAS_EXCEPTION_NAMES */ +PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name, + pj_exception_id_t *id) +{ + PJ_ASSERT_RETURN(last_exception_id < PJ_MAX_EXCEPTION_ID-1, PJ_ETOOMANY); + + *id = last_exception_id++ + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_exception_id_free( pj_exception_id_t id ) +{ + return PJ_SUCCESS; +} + +PJ_DEF(const char*) pj_exception_id_name(pj_exception_id_t id) +{ + return ""; +} + +#endif /* PJ_HAS_EXCEPTION_NAMES */ + + + diff --git a/pjlib/src/pj/extra-exports.c b/pjlib/src/pj/extra-exports.c index 4cc12e3f..83e88f96 100644 --- a/pjlib/src/pj/extra-exports.c +++ b/pjlib/src/pj/extra-exports.c @@ -1,38 +1,38 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/extra-exports.c 1 10/29/05 11:56a Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pj/extra-exports.c $ - * - * 1 10/29/05 11:56a Bennylp - * Version 0.3-pre2 - * - */ - -/* - * This file contains code to export extra symbols from Linux kernel. - * It should be copied to Linux kernel source tree and added to - * Linux kernel combilation. - * - * This file is part of PJLIB project. - */ -#include -#include - -EXPORT_SYMBOL(sys_select); - -EXPORT_SYMBOL(sys_epoll_create); -EXPORT_SYMBOL(sys_epoll_ctl); -EXPORT_SYMBOL(sys_epoll_wait); - -EXPORT_SYMBOL(sys_socket); -EXPORT_SYMBOL(sys_bind); -EXPORT_SYMBOL(sys_getpeername); -EXPORT_SYMBOL(sys_getsockname); -EXPORT_SYMBOL(sys_sendto); -EXPORT_SYMBOL(sys_recvfrom); -EXPORT_SYMBOL(sys_getsockopt); -EXPORT_SYMBOL(sys_setsockopt); -EXPORT_SYMBOL(sys_listen); -EXPORT_SYMBOL(sys_shutdown); -EXPORT_SYMBOL(sys_connect); -EXPORT_SYMBOL(sys_accept); - +/* $Header: /pjproject-0.3/pjlib/src/pj/extra-exports.c 1 10/29/05 11:56a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pj/extra-exports.c $ + * + * 1 10/29/05 11:56a Bennylp + * Version 0.3-pre2 + * + */ + +/* + * This file contains code to export extra symbols from Linux kernel. + * It should be copied to Linux kernel source tree and added to + * Linux kernel combilation. + * + * This file is part of PJLIB project. + */ +#include +#include + +EXPORT_SYMBOL(sys_select); + +EXPORT_SYMBOL(sys_epoll_create); +EXPORT_SYMBOL(sys_epoll_ctl); +EXPORT_SYMBOL(sys_epoll_wait); + +EXPORT_SYMBOL(sys_socket); +EXPORT_SYMBOL(sys_bind); +EXPORT_SYMBOL(sys_getpeername); +EXPORT_SYMBOL(sys_getsockname); +EXPORT_SYMBOL(sys_sendto); +EXPORT_SYMBOL(sys_recvfrom); +EXPORT_SYMBOL(sys_getsockopt); +EXPORT_SYMBOL(sys_setsockopt); +EXPORT_SYMBOL(sys_listen); +EXPORT_SYMBOL(sys_shutdown); +EXPORT_SYMBOL(sys_connect); +EXPORT_SYMBOL(sys_accept); + diff --git a/pjlib/src/pj/fifobuf.c b/pjlib/src/pj/fifobuf.c index d0b41a15..c100129c 100644 --- a/pjlib/src/pj/fifobuf.c +++ b/pjlib/src/pj/fifobuf.c @@ -1,182 +1,182 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/fifobuf.c 4 9/17/05 10:37a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/fifobuf.c $ - * - * 4 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include -#include - -#define THIS_FILE "fifobuf" - -#define SZ sizeof(unsigned) - -PJ_DEF(void) -pj_fifobuf_init (pj_fifobuf_t *fifobuf, void *buffer, unsigned size) -{ - PJ_CHECK_STACK(); - - PJ_LOG(6, (THIS_FILE, - "fifobuf_init fifobuf=%p buffer=%p, size=%d", - fifobuf, buffer, size)); - - fifobuf->first = buffer; - fifobuf->last = fifobuf->first + size; - fifobuf->ubegin = fifobuf->uend = fifobuf->first; - fifobuf->full = 0; -} - -PJ_DEF(unsigned) -pj_fifobuf_max_size (pj_fifobuf_t *fifobuf) -{ - unsigned s1, s2; - - PJ_CHECK_STACK(); - - if (fifobuf->uend >= fifobuf->ubegin) { - s1 = fifobuf->last - fifobuf->uend; - s2 = fifobuf->ubegin - fifobuf->first; - } else { - s1 = s2 = fifobuf->ubegin - fifobuf->uend; - } - - return s1full) { - PJ_LOG(6, (THIS_FILE, - "fifobuf_alloc fifobuf=%p, size=%d: full!", - fifobuf, size)); - return NULL; - } - - /* try to allocate from the end part of the fifo */ - if (fifobuf->uend >= fifobuf->ubegin) { - available = fifobuf->last - fifobuf->uend; - if (available >= size+SZ) { - char *ptr = fifobuf->uend; - fifobuf->uend += (size+SZ); - if (fifobuf->uend == fifobuf->last) - fifobuf->uend = fifobuf->first; - if (fifobuf->uend == fifobuf->ubegin) - fifobuf->full = 1; - *(unsigned*)ptr = size+SZ; - ptr += SZ; - - PJ_LOG(6, (THIS_FILE, - "fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p", - fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend)); - return ptr; - } - } - - /* try to allocate from the start part of the fifo */ - start = (fifobuf->uend <= fifobuf->ubegin) ? fifobuf->uend : fifobuf->first; - available = fifobuf->ubegin - start; - if (available >= size+SZ) { - char *ptr = start; - fifobuf->uend = start + size + SZ; - if (fifobuf->uend == fifobuf->ubegin) - fifobuf->full = 1; - *(unsigned*)ptr = size+SZ; - ptr += SZ; - - PJ_LOG(6, (THIS_FILE, - "fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p", - fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend)); - return ptr; - } - - PJ_LOG(6, (THIS_FILE, - "fifobuf_alloc fifobuf=%p, size=%d: no space left! p1=%p, p2=%p", - fifobuf, size, fifobuf->ubegin, fifobuf->uend)); - return NULL; -} - -PJ_DEF(pj_status_t) -pj_fifobuf_unalloc (pj_fifobuf_t *fifobuf, void *buf) -{ - char *ptr = buf; - char *endptr; - unsigned sz; - - PJ_CHECK_STACK(); - - ptr -= SZ; - sz = *(unsigned*)ptr; - - endptr = fifobuf->uend; - if (endptr == fifobuf->first) - endptr = fifobuf->last; - - if (ptr+sz != endptr) { - pj_assert(!"Invalid pointer to undo alloc"); - return -1; - } - - fifobuf->uend = ptr; - fifobuf->full = 0; - - PJ_LOG(6, (THIS_FILE, - "fifobuf_unalloc fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p", - fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend)); - - return 0; -} - -PJ_DEF(pj_status_t) -pj_fifobuf_free (pj_fifobuf_t *fifobuf, void *buf) -{ - char *ptr = buf; - char *end; - unsigned sz; - - PJ_CHECK_STACK(); - - ptr -= SZ; - if (ptr < fifobuf->first || ptr >= fifobuf->last) { - pj_assert(!"Invalid pointer to free"); - return -1; - } - - if (ptr != fifobuf->ubegin && ptr != fifobuf->first) { - pj_assert(!"Invalid free() sequence!"); - return -1; - } - - end = (fifobuf->uend > fifobuf->ubegin) ? fifobuf->uend : fifobuf->last; - sz = *(unsigned*)ptr; - if (ptr+sz > end) { - pj_assert(!"Invalid size!"); - return -1; - } - - fifobuf->ubegin = ptr + sz; - - /* Rollover */ - if (fifobuf->ubegin == fifobuf->last) - fifobuf->ubegin = fifobuf->first; - - /* Reset if fifobuf is empty */ - if (fifobuf->ubegin == fifobuf->uend) - fifobuf->ubegin = fifobuf->uend = fifobuf->first; - - fifobuf->full = 0; - - PJ_LOG(6, (THIS_FILE, - "fifobuf_free fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p", - fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend)); - - return 0; -} +/* $Header: /pjproject-0.3/pjlib/src/pj/fifobuf.c 4 9/17/05 10:37a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/fifobuf.c $ + * + * 4 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include +#include +#include + +#define THIS_FILE "fifobuf" + +#define SZ sizeof(unsigned) + +PJ_DEF(void) +pj_fifobuf_init (pj_fifobuf_t *fifobuf, void *buffer, unsigned size) +{ + PJ_CHECK_STACK(); + + PJ_LOG(6, (THIS_FILE, + "fifobuf_init fifobuf=%p buffer=%p, size=%d", + fifobuf, buffer, size)); + + fifobuf->first = buffer; + fifobuf->last = fifobuf->first + size; + fifobuf->ubegin = fifobuf->uend = fifobuf->first; + fifobuf->full = 0; +} + +PJ_DEF(unsigned) +pj_fifobuf_max_size (pj_fifobuf_t *fifobuf) +{ + unsigned s1, s2; + + PJ_CHECK_STACK(); + + if (fifobuf->uend >= fifobuf->ubegin) { + s1 = fifobuf->last - fifobuf->uend; + s2 = fifobuf->ubegin - fifobuf->first; + } else { + s1 = s2 = fifobuf->ubegin - fifobuf->uend; + } + + return s1full) { + PJ_LOG(6, (THIS_FILE, + "fifobuf_alloc fifobuf=%p, size=%d: full!", + fifobuf, size)); + return NULL; + } + + /* try to allocate from the end part of the fifo */ + if (fifobuf->uend >= fifobuf->ubegin) { + available = fifobuf->last - fifobuf->uend; + if (available >= size+SZ) { + char *ptr = fifobuf->uend; + fifobuf->uend += (size+SZ); + if (fifobuf->uend == fifobuf->last) + fifobuf->uend = fifobuf->first; + if (fifobuf->uend == fifobuf->ubegin) + fifobuf->full = 1; + *(unsigned*)ptr = size+SZ; + ptr += SZ; + + PJ_LOG(6, (THIS_FILE, + "fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p", + fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend)); + return ptr; + } + } + + /* try to allocate from the start part of the fifo */ + start = (fifobuf->uend <= fifobuf->ubegin) ? fifobuf->uend : fifobuf->first; + available = fifobuf->ubegin - start; + if (available >= size+SZ) { + char *ptr = start; + fifobuf->uend = start + size + SZ; + if (fifobuf->uend == fifobuf->ubegin) + fifobuf->full = 1; + *(unsigned*)ptr = size+SZ; + ptr += SZ; + + PJ_LOG(6, (THIS_FILE, + "fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p", + fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend)); + return ptr; + } + + PJ_LOG(6, (THIS_FILE, + "fifobuf_alloc fifobuf=%p, size=%d: no space left! p1=%p, p2=%p", + fifobuf, size, fifobuf->ubegin, fifobuf->uend)); + return NULL; +} + +PJ_DEF(pj_status_t) +pj_fifobuf_unalloc (pj_fifobuf_t *fifobuf, void *buf) +{ + char *ptr = buf; + char *endptr; + unsigned sz; + + PJ_CHECK_STACK(); + + ptr -= SZ; + sz = *(unsigned*)ptr; + + endptr = fifobuf->uend; + if (endptr == fifobuf->first) + endptr = fifobuf->last; + + if (ptr+sz != endptr) { + pj_assert(!"Invalid pointer to undo alloc"); + return -1; + } + + fifobuf->uend = ptr; + fifobuf->full = 0; + + PJ_LOG(6, (THIS_FILE, + "fifobuf_unalloc fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p", + fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend)); + + return 0; +} + +PJ_DEF(pj_status_t) +pj_fifobuf_free (pj_fifobuf_t *fifobuf, void *buf) +{ + char *ptr = buf; + char *end; + unsigned sz; + + PJ_CHECK_STACK(); + + ptr -= SZ; + if (ptr < fifobuf->first || ptr >= fifobuf->last) { + pj_assert(!"Invalid pointer to free"); + return -1; + } + + if (ptr != fifobuf->ubegin && ptr != fifobuf->first) { + pj_assert(!"Invalid free() sequence!"); + return -1; + } + + end = (fifobuf->uend > fifobuf->ubegin) ? fifobuf->uend : fifobuf->last; + sz = *(unsigned*)ptr; + if (ptr+sz > end) { + pj_assert(!"Invalid size!"); + return -1; + } + + fifobuf->ubegin = ptr + sz; + + /* Rollover */ + if (fifobuf->ubegin == fifobuf->last) + fifobuf->ubegin = fifobuf->first; + + /* Reset if fifobuf is empty */ + if (fifobuf->ubegin == fifobuf->uend) + fifobuf->ubegin = fifobuf->uend = fifobuf->first; + + fifobuf->full = 0; + + PJ_LOG(6, (THIS_FILE, + "fifobuf_free fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p", + fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend)); + + return 0; +} diff --git a/pjlib/src/pj/guid.c b/pjlib/src/pj/guid.c index 20cb72a7..e3195d09 100644 --- a/pjlib/src/pj/guid.c +++ b/pjlib/src/pj/guid.c @@ -1,19 +1,19 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/guid.c 12 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/guid.c $ - * - * 12 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 11 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include - -PJ_DEF(void) pj_create_unique_string(pj_pool_t *pool, pj_str_t *str) -{ - str->ptr = pj_pool_alloc(pool, PJ_GUID_STRING_LENGTH); - pj_generate_unique_string(str); -} +/* $Header: /pjproject-0.3/pjlib/src/pj/guid.c 12 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/guid.c $ + * + * 12 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 11 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include + +PJ_DEF(void) pj_create_unique_string(pj_pool_t *pool, pj_str_t *str) +{ + str->ptr = pj_pool_alloc(pool, PJ_GUID_STRING_LENGTH); + pj_generate_unique_string(str); +} diff --git a/pjlib/src/pj/guid_simple.c b/pjlib/src/pj/guid_simple.c index b5cca310..f8024173 100644 --- a/pjlib/src/pj/guid_simple.c +++ b/pjlib/src/pj/guid_simple.c @@ -1,60 +1,60 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/guid_simple.c 3 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/guid_simple.c $ - * - * 3 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include -#include -#include - -const unsigned PJ_GUID_STRING_LENGTH=20; - -static void init_mac_address(unsigned char mac_addr[16]) -{ - unsigned long *ulval1 = (unsigned long*) &mac_addr[0]; - unsigned short *usval1 = (unsigned short*) &mac_addr[4]; - - *ulval1 = pj_rand(); - *usval1 = (unsigned short) pj_rand(); -} - -PJ_DEF(pj_str_t*) pj_generate_unique_string(pj_str_t *str) -{ - static int guid_initialized; - static unsigned pid; - static char str_pid[5]; - static unsigned char mac_addr[6]; - static char str_mac_addr[16]; - static unsigned clock_seq; - - PJ_CHECK_STACK(); - - if (guid_initialized == 0) { - pid = pj_getpid(); - init_mac_address(mac_addr); - clock_seq = 0; - - sprintf(str_pid, "%04x", pid); - sprintf(str_mac_addr, "%02x%02x%02x%02x%02x%02x", - mac_addr[0], mac_addr[1], mac_addr[2], - mac_addr[3], mac_addr[4], mac_addr[5]); - - guid_initialized = 1; - } - - strcpy(str->ptr, str_pid); - sprintf(str->ptr+4, "%04x", clock_seq++); - pj_memcpy(str->ptr+8, str_mac_addr, 12); - str->slen = 20; - - return str; -} - +/* $Header: /pjproject-0.3/pjlib/src/pj/guid_simple.c 3 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/guid_simple.c $ + * + * 3 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 2 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include +#include +#include +#include + +const unsigned PJ_GUID_STRING_LENGTH=20; + +static void init_mac_address(unsigned char mac_addr[16]) +{ + unsigned long *ulval1 = (unsigned long*) &mac_addr[0]; + unsigned short *usval1 = (unsigned short*) &mac_addr[4]; + + *ulval1 = pj_rand(); + *usval1 = (unsigned short) pj_rand(); +} + +PJ_DEF(pj_str_t*) pj_generate_unique_string(pj_str_t *str) +{ + static int guid_initialized; + static unsigned pid; + static char str_pid[5]; + static unsigned char mac_addr[6]; + static char str_mac_addr[16]; + static unsigned clock_seq; + + PJ_CHECK_STACK(); + + if (guid_initialized == 0) { + pid = pj_getpid(); + init_mac_address(mac_addr); + clock_seq = 0; + + sprintf(str_pid, "%04x", pid); + sprintf(str_mac_addr, "%02x%02x%02x%02x%02x%02x", + mac_addr[0], mac_addr[1], mac_addr[2], + mac_addr[3], mac_addr[4], mac_addr[5]); + + guid_initialized = 1; + } + + strcpy(str->ptr, str_pid); + sprintf(str->ptr+4, "%04x", clock_seq++); + pj_memcpy(str->ptr+8, str_mac_addr, 12); + str->slen = 20; + + return str; +} + diff --git a/pjlib/src/pj/guid_win32.c b/pjlib/src/pj/guid_win32.c index 8e3707ec..f2a3f855 100644 --- a/pjlib/src/pj/guid_win32.c +++ b/pjlib/src/pj/guid_win32.c @@ -1,61 +1,61 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/guid_win32.c 4 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/guid_win32.c $ - * - * 4 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 3 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include -#include -#include -#include - - -const unsigned PJ_GUID_STRING_LENGTH=32; - -PJ_INLINE(void) hex2digit(unsigned value, char *p) -{ - static char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - *p++ = hex[ (value & 0xF0) >> 4 ]; - *p++ = hex[ (value & 0x0F) ]; -} - -static void guid_to_str( const GUID *guid, pj_str_t *str ) -{ - unsigned i; - GUID guid_copy; - const unsigned char *src = (const unsigned char*)&guid_copy; - char *dst = str->ptr; - - pj_memcpy(&guid_copy, guid, sizeof(*guid)); - guid_copy.Data1 = pj_ntohl(guid_copy.Data1); - guid_copy.Data2 = pj_ntohs(guid_copy.Data2); - guid_copy.Data3 = pj_ntohs(guid_copy.Data3); - - for (i=0; i<16; ++i) { - hex2digit( *src, dst ); - dst += 2; - ++src; - } - str->slen = 32; -} - - -PJ_DEF(pj_str_t*) pj_generate_unique_string(pj_str_t *str) -{ - GUID guid; - - PJ_CHECK_STACK(); - - CoCreateGuid(&guid); - guid_to_str( &guid, str ); - return str; -} - +/* $Header: /pjproject-0.3/pjlib/src/pj/guid_win32.c 4 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/guid_win32.c $ + * + * 4 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 3 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include +#include +#include +#include +#include + + +const unsigned PJ_GUID_STRING_LENGTH=32; + +PJ_INLINE(void) hex2digit(unsigned value, char *p) +{ + static char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + *p++ = hex[ (value & 0xF0) >> 4 ]; + *p++ = hex[ (value & 0x0F) ]; +} + +static void guid_to_str( const GUID *guid, pj_str_t *str ) +{ + unsigned i; + GUID guid_copy; + const unsigned char *src = (const unsigned char*)&guid_copy; + char *dst = str->ptr; + + pj_memcpy(&guid_copy, guid, sizeof(*guid)); + guid_copy.Data1 = pj_ntohl(guid_copy.Data1); + guid_copy.Data2 = pj_ntohs(guid_copy.Data2); + guid_copy.Data3 = pj_ntohs(guid_copy.Data3); + + for (i=0; i<16; ++i) { + hex2digit( *src, dst ); + dst += 2; + ++src; + } + str->slen = 32; +} + + +PJ_DEF(pj_str_t*) pj_generate_unique_string(pj_str_t *str) +{ + GUID guid; + + PJ_CHECK_STACK(); + + CoCreateGuid(&guid); + guid_to_str( &guid, str ); + return str; +} + diff --git a/pjlib/src/pj/hash.c b/pjlib/src/pj/hash.c index 01bfaa6b..69b577d3 100644 --- a/pjlib/src/pj/hash.c +++ b/pjlib/src/pj/hash.c @@ -1,252 +1,252 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/hash.c 8 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/hash.c $ - * - * 8 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 7 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include -#include -#include - -/** - * The hash multiplier used to calculate hash value. - */ -#define PJ_HASH_MULTIPLIER 33 - - -struct pj_hash_entry -{ - struct pj_hash_entry *next; - const void *key; - pj_uint32_t hash; - pj_uint32_t keylen; - void *value; -}; - - -struct pj_hash_table_t -{ - pj_hash_entry **table; - unsigned count, rows; - pj_hash_iterator_t iterator; -}; - - - -PJ_DEF(pj_uint32_t) pj_hash_calc(pj_uint32_t hash, const void *key, unsigned keylen) -{ - PJ_CHECK_STACK(); - - if (keylen==PJ_HASH_KEY_STRING) { - const unsigned char *p = key; - for ( ; *p; ++p ) { - hash = hash * PJ_HASH_MULTIPLIER + *p; - } - keylen = p - (const unsigned char*)key; - } else { - const unsigned char *p = key, - *end = p + keylen; - for ( ; p!=end; ++p) { - hash = hash * PJ_HASH_MULTIPLIER + *p; - } - } - return hash; -} - - -PJ_DEF(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size) -{ - pj_hash_table_t *h; - unsigned table_size; - - h = pj_pool_alloc(pool, sizeof(pj_hash_table_t)); - h->count = 0; - - PJ_LOG( 5, ("hashtbl", "hash table %p created from pool %s", h, pj_pool_getobjname(pool))); - - /* size must be 2^n - 1. - round-up the size to this rule, except when size is 2^n, then size - will be round-down to 2^n-1. - */ - table_size = 8; - do { - table_size <<= 1; - } while (table_size <= size); - table_size -= 1; - - h->rows = table_size; - h->table = pj_pool_calloc(pool, table_size+1, sizeof(pj_hash_entry*)); - return h; -} - -static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht, - const void *key, unsigned keylen, - void *val) -{ - pj_uint32_t hash; - pj_hash_entry **p_entry, *entry; - - hash=0; - if (keylen==PJ_HASH_KEY_STRING) { - const unsigned char *p = key; - for ( ; *p; ++p ) { - hash = hash * PJ_HASH_MULTIPLIER + *p; - } - keylen = p - (const unsigned char*)key; - } else { - const unsigned char *p = key, - *end = p + keylen; - for ( ; p!=end; ++p) { - hash = hash * PJ_HASH_MULTIPLIER + *p; - } - } - - /* scan the linked list */ - for (p_entry = &ht->table[hash & ht->rows], entry=*p_entry; - entry; - p_entry = &entry->next, entry = *p_entry) - { - if (entry->hash==hash && entry->keylen==keylen && - memcmp(entry->key, key, keylen)==0) - { - break; - } - } - - if (entry || val==NULL) - return p_entry; - - /* create a new entry */ - entry = pj_pool_alloc(pool, sizeof(pj_hash_entry)); - PJ_LOG(5, ("hashtbl", "%p: New p_entry %p created, pool used=%u, cap=%u", ht, entry, - pj_pool_get_used_size(pool), pj_pool_get_capacity(pool))); - entry->next = NULL; - entry->hash = hash; - entry->key = key; - entry->keylen = keylen; - entry->value = val; - *p_entry = entry; - - ++ht->count; - - return p_entry; -} - -PJ_DEF(void *) pj_hash_get( pj_hash_table_t *ht, - const void *key, unsigned keylen ) -{ - pj_hash_entry *entry; - entry = *find_entry( NULL, ht, key, keylen, NULL); - return entry ? entry->value : NULL; -} - -PJ_DEF(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht, - const void *key, unsigned keylen, - void *value ) -{ - pj_hash_entry **p_entry; - - p_entry = find_entry( pool, ht, key, keylen, value ); - if (*p_entry) { - if (value == NULL) { - /* delete entry */ - PJ_LOG(5, ("hashtbl", "%p: p_entry %p deleted", ht, *p_entry)); - *p_entry = (*p_entry)->next; - --ht->count; - - } else { - /* overwrite */ - (*p_entry)->value = value; - PJ_LOG(5, ("hashtbl", "%p: p_entry %p value set to %p", ht, *p_entry, value)); - } - } -} - -PJ_DEF(unsigned) pj_hash_count( pj_hash_table_t *ht ) -{ - return ht->count; -} - -PJ_DEF(pj_hash_iterator_t*) pj_hash_first( pj_hash_table_t *ht, - pj_hash_iterator_t *it ) -{ - it->index = 0; - it->entry = NULL; - - for (; it->index < ht->rows; ++it->index) { - it->entry = ht->table[it->index]; - if (it->entry) { - break; - } - } - - return it->entry ? it : NULL; -} - -PJ_DEF(pj_hash_iterator_t*) pj_hash_next( pj_hash_table_t *ht, - pj_hash_iterator_t *it ) -{ - it->entry = it->entry->next; - if (it->entry) { - return it; - } - - for (++it->index; it->index < ht->rows; ++it->index) { - it->entry = ht->table[it->index]; - if (it->entry) { - break; - } - } - - return it->entry ? it : NULL; -} - -PJ_DEF(void*) pj_hash_this( pj_hash_table_t *ht, pj_hash_iterator_t *it ) -{ - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(ht); - return it->entry->value; -} - -#if 0 -void pj_hash_dump_collision( pj_hash_table_t *ht ) -{ - unsigned min=0xFFFFFFFF, max=0; - unsigned i; - char line[120]; - int len, totlen = 0; - - for (i=0; irows; ++i) { - unsigned count = 0; - pj_hash_entry *entry = ht->table[i]; - while (entry) { - ++count; - entry = entry->next; - } - if (count < min) - min = count; - if (count > max) - max = count; - len = pj_snprintf( line+totlen, sizeof(line)-totlen, "%3d:%3d ", i, count); - if (len < 1) - break; - totlen += len; - - if ((i+1) % 10 == 0) { - line[totlen] = '\0'; - PJ_LOG(4,(__FILE__, line)); - } - } - - PJ_LOG(4,(__FILE__,"Count: %d, min: %d, max: %d\n", ht->count, min, max)); -} -#endif - - +/* $Header: /pjproject-0.3/pjlib/src/pj/hash.c 8 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/hash.c $ + * + * 8 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 7 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include +#include +#include +#include + +/** + * The hash multiplier used to calculate hash value. + */ +#define PJ_HASH_MULTIPLIER 33 + + +struct pj_hash_entry +{ + struct pj_hash_entry *next; + const void *key; + pj_uint32_t hash; + pj_uint32_t keylen; + void *value; +}; + + +struct pj_hash_table_t +{ + pj_hash_entry **table; + unsigned count, rows; + pj_hash_iterator_t iterator; +}; + + + +PJ_DEF(pj_uint32_t) pj_hash_calc(pj_uint32_t hash, const void *key, unsigned keylen) +{ + PJ_CHECK_STACK(); + + if (keylen==PJ_HASH_KEY_STRING) { + const unsigned char *p = key; + for ( ; *p; ++p ) { + hash = hash * PJ_HASH_MULTIPLIER + *p; + } + keylen = p - (const unsigned char*)key; + } else { + const unsigned char *p = key, + *end = p + keylen; + for ( ; p!=end; ++p) { + hash = hash * PJ_HASH_MULTIPLIER + *p; + } + } + return hash; +} + + +PJ_DEF(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size) +{ + pj_hash_table_t *h; + unsigned table_size; + + h = pj_pool_alloc(pool, sizeof(pj_hash_table_t)); + h->count = 0; + + PJ_LOG( 5, ("hashtbl", "hash table %p created from pool %s", h, pj_pool_getobjname(pool))); + + /* size must be 2^n - 1. + round-up the size to this rule, except when size is 2^n, then size + will be round-down to 2^n-1. + */ + table_size = 8; + do { + table_size <<= 1; + } while (table_size <= size); + table_size -= 1; + + h->rows = table_size; + h->table = pj_pool_calloc(pool, table_size+1, sizeof(pj_hash_entry*)); + return h; +} + +static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht, + const void *key, unsigned keylen, + void *val) +{ + pj_uint32_t hash; + pj_hash_entry **p_entry, *entry; + + hash=0; + if (keylen==PJ_HASH_KEY_STRING) { + const unsigned char *p = key; + for ( ; *p; ++p ) { + hash = hash * PJ_HASH_MULTIPLIER + *p; + } + keylen = p - (const unsigned char*)key; + } else { + const unsigned char *p = key, + *end = p + keylen; + for ( ; p!=end; ++p) { + hash = hash * PJ_HASH_MULTIPLIER + *p; + } + } + + /* scan the linked list */ + for (p_entry = &ht->table[hash & ht->rows], entry=*p_entry; + entry; + p_entry = &entry->next, entry = *p_entry) + { + if (entry->hash==hash && entry->keylen==keylen && + memcmp(entry->key, key, keylen)==0) + { + break; + } + } + + if (entry || val==NULL) + return p_entry; + + /* create a new entry */ + entry = pj_pool_alloc(pool, sizeof(pj_hash_entry)); + PJ_LOG(5, ("hashtbl", "%p: New p_entry %p created, pool used=%u, cap=%u", ht, entry, + pj_pool_get_used_size(pool), pj_pool_get_capacity(pool))); + entry->next = NULL; + entry->hash = hash; + entry->key = key; + entry->keylen = keylen; + entry->value = val; + *p_entry = entry; + + ++ht->count; + + return p_entry; +} + +PJ_DEF(void *) pj_hash_get( pj_hash_table_t *ht, + const void *key, unsigned keylen ) +{ + pj_hash_entry *entry; + entry = *find_entry( NULL, ht, key, keylen, NULL); + return entry ? entry->value : NULL; +} + +PJ_DEF(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht, + const void *key, unsigned keylen, + void *value ) +{ + pj_hash_entry **p_entry; + + p_entry = find_entry( pool, ht, key, keylen, value ); + if (*p_entry) { + if (value == NULL) { + /* delete entry */ + PJ_LOG(5, ("hashtbl", "%p: p_entry %p deleted", ht, *p_entry)); + *p_entry = (*p_entry)->next; + --ht->count; + + } else { + /* overwrite */ + (*p_entry)->value = value; + PJ_LOG(5, ("hashtbl", "%p: p_entry %p value set to %p", ht, *p_entry, value)); + } + } +} + +PJ_DEF(unsigned) pj_hash_count( pj_hash_table_t *ht ) +{ + return ht->count; +} + +PJ_DEF(pj_hash_iterator_t*) pj_hash_first( pj_hash_table_t *ht, + pj_hash_iterator_t *it ) +{ + it->index = 0; + it->entry = NULL; + + for (; it->index < ht->rows; ++it->index) { + it->entry = ht->table[it->index]; + if (it->entry) { + break; + } + } + + return it->entry ? it : NULL; +} + +PJ_DEF(pj_hash_iterator_t*) pj_hash_next( pj_hash_table_t *ht, + pj_hash_iterator_t *it ) +{ + it->entry = it->entry->next; + if (it->entry) { + return it; + } + + for (++it->index; it->index < ht->rows; ++it->index) { + it->entry = ht->table[it->index]; + if (it->entry) { + break; + } + } + + return it->entry ? it : NULL; +} + +PJ_DEF(void*) pj_hash_this( pj_hash_table_t *ht, pj_hash_iterator_t *it ) +{ + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(ht); + return it->entry->value; +} + +#if 0 +void pj_hash_dump_collision( pj_hash_table_t *ht ) +{ + unsigned min=0xFFFFFFFF, max=0; + unsigned i; + char line[120]; + int len, totlen = 0; + + for (i=0; irows; ++i) { + unsigned count = 0; + pj_hash_entry *entry = ht->table[i]; + while (entry) { + ++count; + entry = entry->next; + } + if (count < min) + min = count; + if (count > max) + max = count; + len = pj_snprintf( line+totlen, sizeof(line)-totlen, "%3d:%3d ", i, count); + if (len < 1) + break; + totlen += len; + + if ((i+1) % 10 == 0) { + line[totlen] = '\0'; + PJ_LOG(4,(__FILE__, line)); + } + } + + PJ_LOG(4,(__FILE__,"Count: %d, min: %d, max: %d\n", ht->count, min, max)); +} +#endif + + diff --git a/pjlib/src/pj/ioqueue_dummy.c b/pjlib/src/pj/ioqueue_dummy.c index 63abc15b..125994da 100644 --- a/pjlib/src/pj/ioqueue_dummy.c +++ b/pjlib/src/pj/ioqueue_dummy.c @@ -1,186 +1,186 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/ioqueue_dummy.c 2 10/29/05 11:31a Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pj/ioqueue_dummy.c $ - * - * 2 10/29/05 11:31a Bennylp - * Changed accept and lock. - * - * 1 10/23/05 12:53p Bennylp - * Created. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define THIS_FILE "ioqueue" - -#define PJ_IOQUEUE_IS_READ_OP(op) \ - ((op & PJ_IOQUEUE_OP_READ) || (op & PJ_IOQUEUE_OP_RECV_FROM)) -#define PJ_IOQUEUE_IS_WRITE_OP(op) \ - ((op & PJ_IOQUEUE_OP_WRITE) || (op & PJ_IOQUEUE_OP_SEND_TO)) - - -#if PJ_HAS_TCP -# define PJ_IOQUEUE_IS_ACCEPT_OP(op) (op & PJ_IOQUEUE_OP_ACCEPT) -# define PJ_IOQUEUE_IS_CONNECT_OP(op) (op & PJ_IOQUEUE_OP_CONNECT) -#else -# define PJ_IOQUEUE_IS_ACCEPT_OP(op) 0 -# define PJ_IOQUEUE_IS_CONNECT_OP(op) 0 -#endif - -#if defined(PJ_DEBUG) && PJ_DEBUG != 0 -# define VALIDATE_FD_SET 1 -#else -# define VALIDATE_FD_SET 0 -#endif - -struct pj_ioqueue_key_t -{ - PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t) - pj_sock_t fd; - pj_ioqueue_operation_e op; - void *user_data; - pj_ioqueue_callback cb; -}; - -struct pj_ioqueue_t -{ -}; - -PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, - pj_size_t max_fd, - int max_threads, - pj_ioqueue_t **ptr_ioqueue) -{ - return PJ_ENOTSUP; -} - -PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque) -{ - return PJ_ENOTSUP; -} - -PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, - pj_lock_t *lock, - pj_bool_t auto_delete ) -{ - return PJ_ENOTSUP; -} - -PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool, - pj_ioqueue_t *ioque, - pj_sock_t sock, - void *user_data, - const pj_ioqueue_callback *cb, - pj_ioqueue_key_t **ptr_key) -{ - return PJ_ENOTSUP; -} - -PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key) -{ - return PJ_ENOTSUP; -} - -PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key ) -{ - return NULL; -} - - -PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout) -{ - return -1; -} - -PJ_DEF(pj_status_t) pj_ioqueue_read( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - void *buffer, - pj_size_t buflen) -{ - return -1; -} - -PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - void *buffer, - pj_size_t buflen, - unsigned flags) -{ - return -1; -} - -PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - void *buffer, - pj_size_t buflen, - unsigned flags, - pj_sockaddr_t *addr, - int *addrlen) -{ - return -1; -} - -PJ_DEF(pj_status_t) pj_ioqueue_write( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - const void *data, - pj_size_t datalen) -{ - return -1; -} - -PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - const void *data, - pj_size_t datalen, - unsigned flags) -{ - return -1; -} - -PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - const void *data, - pj_size_t datalen, - unsigned flags, - const pj_sockaddr_t *addr, - int addrlen) -{ - return -1; -} - -#if PJ_HAS_TCP -/* - * Initiate overlapped accept() operation. - */ -PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_t *ioqueue, - pj_ioqueue_key_t *key, - pj_sock_t *new_sock, - pj_sockaddr_t *local, - pj_sockaddr_t *remote, - int *addrlen) -{ - return -1; -} - -/* - * Initiate overlapped connect() operation (well, it's non-blocking actually, - * since there's no overlapped version of connect()). - */ -PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue, - pj_ioqueue_key_t *key, - const pj_sockaddr_t *addr, - int addrlen ) -{ - return -1; -} -#endif /* PJ_HAS_TCP */ - +/* $Header: /pjproject-0.3/pjlib/src/pj/ioqueue_dummy.c 2 10/29/05 11:31a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pj/ioqueue_dummy.c $ + * + * 2 10/29/05 11:31a Bennylp + * Changed accept and lock. + * + * 1 10/23/05 12:53p Bennylp + * Created. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define THIS_FILE "ioqueue" + +#define PJ_IOQUEUE_IS_READ_OP(op) \ + ((op & PJ_IOQUEUE_OP_READ) || (op & PJ_IOQUEUE_OP_RECV_FROM)) +#define PJ_IOQUEUE_IS_WRITE_OP(op) \ + ((op & PJ_IOQUEUE_OP_WRITE) || (op & PJ_IOQUEUE_OP_SEND_TO)) + + +#if PJ_HAS_TCP +# define PJ_IOQUEUE_IS_ACCEPT_OP(op) (op & PJ_IOQUEUE_OP_ACCEPT) +# define PJ_IOQUEUE_IS_CONNECT_OP(op) (op & PJ_IOQUEUE_OP_CONNECT) +#else +# define PJ_IOQUEUE_IS_ACCEPT_OP(op) 0 +# define PJ_IOQUEUE_IS_CONNECT_OP(op) 0 +#endif + +#if defined(PJ_DEBUG) && PJ_DEBUG != 0 +# define VALIDATE_FD_SET 1 +#else +# define VALIDATE_FD_SET 0 +#endif + +struct pj_ioqueue_key_t +{ + PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t) + pj_sock_t fd; + pj_ioqueue_operation_e op; + void *user_data; + pj_ioqueue_callback cb; +}; + +struct pj_ioqueue_t +{ +}; + +PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, + pj_size_t max_fd, + int max_threads, + pj_ioqueue_t **ptr_ioqueue) +{ + return PJ_ENOTSUP; +} + +PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque) +{ + return PJ_ENOTSUP; +} + +PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, + pj_lock_t *lock, + pj_bool_t auto_delete ) +{ + return PJ_ENOTSUP; +} + +PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool, + pj_ioqueue_t *ioque, + pj_sock_t sock, + void *user_data, + const pj_ioqueue_callback *cb, + pj_ioqueue_key_t **ptr_key) +{ + return PJ_ENOTSUP; +} + +PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key) +{ + return PJ_ENOTSUP; +} + +PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key ) +{ + return NULL; +} + + +PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout) +{ + return -1; +} + +PJ_DEF(pj_status_t) pj_ioqueue_read( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + void *buffer, + pj_size_t buflen) +{ + return -1; +} + +PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + void *buffer, + pj_size_t buflen, + unsigned flags) +{ + return -1; +} + +PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + void *buffer, + pj_size_t buflen, + unsigned flags, + pj_sockaddr_t *addr, + int *addrlen) +{ + return -1; +} + +PJ_DEF(pj_status_t) pj_ioqueue_write( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + const void *data, + pj_size_t datalen) +{ + return -1; +} + +PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + const void *data, + pj_size_t datalen, + unsigned flags) +{ + return -1; +} + +PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + const void *data, + pj_size_t datalen, + unsigned flags, + const pj_sockaddr_t *addr, + int addrlen) +{ + return -1; +} + +#if PJ_HAS_TCP +/* + * Initiate overlapped accept() operation. + */ +PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_t *ioqueue, + pj_ioqueue_key_t *key, + pj_sock_t *new_sock, + pj_sockaddr_t *local, + pj_sockaddr_t *remote, + int *addrlen) +{ + return -1; +} + +/* + * Initiate overlapped connect() operation (well, it's non-blocking actually, + * since there's no overlapped version of connect()). + */ +PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue, + pj_ioqueue_key_t *key, + const pj_sockaddr_t *addr, + int addrlen ) +{ + return -1; +} +#endif /* PJ_HAS_TCP */ + diff --git a/pjlib/src/pj/ioqueue_epoll.c b/pjlib/src/pj/ioqueue_epoll.c index 7bbfe135..b41d05f0 100644 --- a/pjlib/src/pj/ioqueue_epoll.c +++ b/pjlib/src/pj/ioqueue_epoll.c @@ -1,852 +1,852 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/ioqueue_epoll.c 4 10/29/05 10:27p Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pj/ioqueue_epoll.c $ - * - * 4 10/29/05 10:27p Bennylp - * Fixed misc warnings. - * - * 3 10/29/05 11:49a Bennylp - * Fixed warnings. - * - * 2 10/29/05 11:31a Bennylp - * Changed accept and lock. - * - * 1 10/17/05 10:49p Bennylp - * Created. - * - */ - -/* - * ioqueue_epoll.c - * - * This is the implementation of IOQueue framework using /dev/epoll - * API in _both_ Linux user-mode and kernel-mode. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if !defined(PJ_LINUX_KERNEL) || PJ_LINUX_KERNEL==0 - /* - * Linux user mode - */ -# include -# include -# include - -# define epoll_data data.ptr -# define epoll_data_type void* -# define ioctl_val_type unsigned long* -# define getsockopt_val_ptr int* -# define os_getsockopt getsockopt -# define os_ioctl ioctl -# define os_read read -# define os_close close -# define os_epoll_create epoll_create -# define os_epoll_ctl epoll_ctl -# define os_epoll_wait epoll_wait -#else - /* - * Linux kernel mode. - */ -# include -# include -# if defined(MODVERSIONS) -# include -# endif -# include -# include -# include -# include -# include -# include -# include - enum EPOLL_EVENTS - { - EPOLLIN = 0x001, - EPOLLOUT = 0x004, - EPOLLERR = 0x008, - }; -# define os_epoll_create sys_epoll_create - static int os_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) - { - long rc; - mm_segment_t oldfs = get_fs(); - set_fs(KERNEL_DS); - rc = sys_epoll_ctl(epfd, op, fd, event); - set_fs(oldfs); - if (rc) { - errno = -rc; - return -1; - } else { - return 0; - } - } - static int os_epoll_wait(int epfd, struct epoll_event *events, - int maxevents, int timeout) - { - int count; - mm_segment_t oldfs = get_fs(); - set_fs(KERNEL_DS); - count = sys_epoll_wait(epfd, events, maxevents, timeout); - set_fs(oldfs); - return count; - } -# define os_close sys_close -# define os_getsockopt pj_sock_getsockopt - static int os_read(int fd, void *buf, size_t len) - { - long rc; - mm_segment_t oldfs = get_fs(); - set_fs(KERNEL_DS); - rc = sys_read(fd, buf, len); - set_fs(oldfs); - if (rc) { - errno = -rc; - return -1; - } else { - return 0; - } - } -# define socklen_t unsigned -# define ioctl_val_type unsigned long - int ioctl(int fd, int opt, ioctl_val_type value); - static int os_ioctl(int fd, int opt, ioctl_val_type value) - { - int rc; - mm_segment_t oldfs = get_fs(); - set_fs(KERNEL_DS); - rc = ioctl(fd, opt, value); - set_fs(oldfs); - if (rc < 0) { - errno = -rc; - return rc; - } else - return rc; - } -# define getsockopt_val_ptr char* - -# define epoll_data data -# define epoll_data_type __u32 -#endif - -#define THIS_FILE "ioq_epoll" - -#define PJ_IOQUEUE_IS_READ_OP(op) ((op & PJ_IOQUEUE_OP_READ) || \ - (op & PJ_IOQUEUE_OP_RECV) || \ - (op & PJ_IOQUEUE_OP_RECV_FROM)) -#define PJ_IOQUEUE_IS_WRITE_OP(op) ((op & PJ_IOQUEUE_OP_WRITE) || \ - (op & PJ_IOQUEUE_OP_SEND) || \ - (op & PJ_IOQUEUE_OP_SEND_TO)) - - -#if PJ_HAS_TCP -# define PJ_IOQUEUE_IS_ACCEPT_OP(op) (op & PJ_IOQUEUE_OP_ACCEPT) -# define PJ_IOQUEUE_IS_CONNECT_OP(op) (op & PJ_IOQUEUE_OP_CONNECT) -#else -# define PJ_IOQUEUE_IS_ACCEPT_OP(op) 0 -# define PJ_IOQUEUE_IS_CONNECT_OP(op) 0 -#endif - - -//#define TRACE_(expr) PJ_LOG(3,expr) -#define TRACE_(expr) - - -/* - * This describes each key. - */ -struct pj_ioqueue_key_t -{ - PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t) - pj_sock_t fd; - pj_ioqueue_operation_e op; - void *user_data; - pj_ioqueue_callback cb; - - void *rd_buf; - unsigned rd_flags; - pj_size_t rd_buflen; - void *wr_buf; - pj_size_t wr_buflen; - - pj_sockaddr_t *rmt_addr; - int *rmt_addrlen; - - pj_sockaddr_t *local_addr; - int *local_addrlen; - - pj_sock_t *accept_fd; -}; - -/* - * This describes the I/O queue. - */ -struct pj_ioqueue_t -{ - pj_lock_t *lock; - pj_bool_t auto_delete_lock; - unsigned max, count; - pj_ioqueue_key_t hlist; - int epfd; -}; - -/* - * pj_ioqueue_create() - * - * Create select ioqueue. - */ -PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, - pj_size_t max_fd, - int max_threads, - pj_ioqueue_t **p_ioqueue) -{ - pj_ioqueue_t *ioque; - pj_status_t rc; - - PJ_UNUSED_ARG(max_threads); - - if (max_fd > PJ_IOQUEUE_MAX_HANDLES) { - pj_assert(!"max_fd too large"); - return PJ_EINVAL; - } - - ioque = pj_pool_alloc(pool, sizeof(pj_ioqueue_t)); - ioque->max = max_fd; - ioque->count = 0; - pj_list_init(&ioque->hlist); - - rc = pj_lock_create_recursive_mutex(pool, "ioq%p", &ioque->lock); - if (rc != PJ_SUCCESS) - return rc; - - ioque->auto_delete_lock = PJ_TRUE; - ioque->epfd = os_epoll_create(max_fd); - if (ioque->epfd < 0) { - return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); - } - - PJ_LOG(4, ("pjlib", "select() I/O Queue created (%p)", ioque)); - - *p_ioqueue = ioque; - return PJ_SUCCESS; -} - -/* - * pj_ioqueue_destroy() - * - * Destroy ioqueue. - */ -PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque) -{ - PJ_ASSERT_RETURN(ioque, PJ_EINVAL); - PJ_ASSERT_RETURN(ioque->epfd > 0, PJ_EINVALIDOP); - - pj_lock_acquire(ioque->lock); - os_close(ioque->epfd); - ioque->epfd = 0; - if (ioque->auto_delete_lock) - pj_lock_destroy(ioque->lock); - - return PJ_SUCCESS; -} - -/* - * pj_ioqueue_set_lock() - */ -PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, - pj_lock_t *lock, - pj_bool_t auto_delete ) -{ - PJ_ASSERT_RETURN(ioque && lock, PJ_EINVAL); - - if (ioque->auto_delete_lock) { - pj_lock_destroy(ioque->lock); - } - - ioque->lock = lock; - ioque->auto_delete_lock = auto_delete; - - return PJ_SUCCESS; -} - - -/* - * pj_ioqueue_register_sock() - * - * Register a socket to ioqueue. - */ -PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool, - pj_ioqueue_t *ioque, - pj_sock_t sock, - void *user_data, - const pj_ioqueue_callback *cb, - pj_ioqueue_key_t **p_key) -{ - pj_ioqueue_key_t *key = NULL; - pj_uint32_t value; - struct epoll_event ev; - int status; - pj_status_t rc = PJ_SUCCESS; - - PJ_ASSERT_RETURN(pool && ioque && sock != PJ_INVALID_SOCKET && - cb && p_key, PJ_EINVAL); - - pj_lock_acquire(ioque->lock); - - if (ioque->count >= ioque->max) { - rc = PJ_ETOOMANY; - TRACE_((THIS_FILE, "pj_ioqueue_register_sock error: too many files")); - goto on_return; - } - - /* Set socket to nonblocking. */ - value = 1; - if ((rc=os_ioctl(sock, FIONBIO, (ioctl_val_type)&value))) { - TRACE_((THIS_FILE, "pj_ioqueue_register_sock error: ioctl rc=%d", - rc)); - rc = pj_get_netos_error(); - goto on_return; - } - - /* Create key. */ - key = (pj_ioqueue_key_t*)pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t)); - key->fd = sock; - key->user_data = user_data; - pj_memcpy(&key->cb, cb, sizeof(pj_ioqueue_callback)); - - /* os_epoll_ctl. */ - ev.events = EPOLLIN | EPOLLOUT | EPOLLERR; - ev.epoll_data = (epoll_data_type)key; - status = os_epoll_ctl(ioque->epfd, EPOLL_CTL_ADD, sock, &ev); - if (status < 0) { - rc = pj_get_os_error(); - TRACE_((THIS_FILE, - "pj_ioqueue_register_sock error: os_epoll_ctl rc=%d", - status)); - goto on_return; - } - - /* Register */ - pj_list_insert_before(&ioque->hlist, key); - ++ioque->count; - -on_return: - *p_key = key; - pj_lock_release(ioque->lock); - - return rc; -} - -/* - * pj_ioqueue_unregister() - * - * Unregister handle from ioqueue. - */ -PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key) -{ - struct epoll_event ev; - int status; - - PJ_ASSERT_RETURN(ioque && key, PJ_EINVAL); - - pj_lock_acquire(ioque->lock); - - pj_assert(ioque->count > 0); - --ioque->count; - pj_list_erase(key); - - ev.events = 0; - ev.epoll_data = (epoll_data_type)key; - status = os_epoll_ctl( ioque->epfd, EPOLL_CTL_DEL, key->fd, &ev); - if (status != 0) { - pj_status_t rc = pj_get_os_error(); - pj_lock_release(ioque->lock); - return rc; - } - - pj_lock_release(ioque->lock); - return PJ_SUCCESS; -} - -/* - * pj_ioqueue_get_user_data() - * - * Obtain value associated with a key. - */ -PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key ) -{ - PJ_ASSERT_RETURN(key != NULL, NULL); - return key->user_data; -} - - -/* - * pj_ioqueue_poll() - * - */ -PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout) -{ - int i, count, processed; - struct epoll_event events[16]; - int msec; - - PJ_CHECK_STACK(); - - msec = timeout ? PJ_TIME_VAL_MSEC(*timeout) : 9000; - - count = os_epoll_wait( ioque->epfd, events, PJ_ARRAY_SIZE(events), msec); - if (count <= 0) - return count; - - /* Lock ioqueue. */ - pj_lock_acquire(ioque->lock); - - processed = 0; - - for (i=0; iop))) { - pj_ssize_t bytes_read = h->rd_buflen; - - if ((h->op & PJ_IOQUEUE_OP_RECV_FROM)) { - rc = pj_sock_recvfrom( h->fd, h->rd_buf, &bytes_read, 0, - h->rmt_addr, h->rmt_addrlen); - } else if ((h->op & PJ_IOQUEUE_OP_RECV)) { - rc = pj_sock_recv(h->fd, h->rd_buf, &bytes_read, 0); - } else { - bytes_read = os_read( h->fd, h->rd_buf, bytes_read); - rc = (bytes_read >= 0) ? PJ_SUCCESS : pj_get_os_error(); - } - - if (rc != PJ_SUCCESS) { - bytes_read = -rc; - } - - h->op &= ~(PJ_IOQUEUE_OP_READ | PJ_IOQUEUE_OP_RECV | - PJ_IOQUEUE_OP_RECV_FROM); - - /* Call callback. */ - (*h->cb.on_read_complete)(h, bytes_read); - - ++processed; - } - /* - * Check for completion of accept() operation. - */ - else if ((events[i].events & EPOLLIN) && - (h->op & PJ_IOQUEUE_OP_ACCEPT)) - { - /* accept() must be the only operation specified on - * server socket - */ - pj_assert( h->op == PJ_IOQUEUE_OP_ACCEPT); - - rc = pj_sock_accept( h->fd, h->accept_fd, - h->rmt_addr, h->rmt_addrlen); - if (rc==PJ_SUCCESS && h->local_addr) { - rc = pj_sock_getsockname(*h->accept_fd, h->local_addr, - h->local_addrlen); - } - - h->op &= ~(PJ_IOQUEUE_OP_ACCEPT); - - /* Call callback. */ - (*h->cb.on_accept_complete)(h, *h->accept_fd, rc); - - ++processed; - } - - /* - * Check for completion of write operations. - */ - if ((events[i].events & EPOLLOUT) && PJ_IOQUEUE_IS_WRITE_OP(h->op)) { - /* Completion of write(), send(), or sendto() operation. */ - - /* Clear operation. */ - h->op &= ~(PJ_IOQUEUE_OP_WRITE | PJ_IOQUEUE_OP_SEND | - PJ_IOQUEUE_OP_SEND_TO); - - /* Call callback. */ - /* All data must have been sent? */ - (*h->cb.on_write_complete)(h, h->wr_buflen); - - ++processed; - } -#if PJ_HAS_TCP - /* - * Check for completion of connect() operation. - */ - else if ((events[i].events & EPOLLOUT) && - (h->op & PJ_IOQUEUE_OP_CONNECT)) - { - /* Completion of connect() operation */ - pj_ssize_t bytes_transfered; - - /* from connect(2): - * On Linux, use getsockopt to read the SO_ERROR option at - * level SOL_SOCKET to determine whether connect() completed - * successfully (if SO_ERROR is zero). - */ - int value; - socklen_t vallen = sizeof(value); - int gs_rc = os_getsockopt(h->fd, SOL_SOCKET, SO_ERROR, - (getsockopt_val_ptr)&value, &vallen); - if (gs_rc != 0) { - /* Argh!! What to do now??? - * Just indicate that the socket is connected. The - * application will get error as soon as it tries to use - * the socket to send/receive. - */ - bytes_transfered = 0; - } else { - bytes_transfered = value; - } - - /* Clear operation. */ - h->op &= (~PJ_IOQUEUE_OP_CONNECT); - - /* Call callback. */ - (*h->cb.on_connect_complete)(h, bytes_transfered); - - ++processed; - } -#endif /* PJ_HAS_TCP */ - - /* - * Check for error condition. - */ - if (events[i].events & EPOLLERR) { - if (h->op & PJ_IOQUEUE_OP_CONNECT) { - h->op &= ~PJ_IOQUEUE_OP_CONNECT; - - /* Call callback. */ - (*h->cb.on_connect_complete)(h, -1); - - ++processed; - } - } - } - - pj_lock_release(ioque->lock); - - return processed; -} - -/* - * pj_ioqueue_read() - * - * Start asynchronous read from the descriptor. - */ -PJ_DEF(pj_status_t) pj_ioqueue_read( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - void *buffer, - pj_size_t buflen) -{ - PJ_ASSERT_RETURN(ioque && key && buffer, PJ_EINVAL); - PJ_CHECK_STACK(); - - /* For consistency with other ioqueue implementation, we would reject - * if descriptor has already been submitted for reading before. - */ - PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_READ) == 0 && - (key->op & PJ_IOQUEUE_OP_RECV) == 0 && - (key->op & PJ_IOQUEUE_OP_RECV_FROM) == 0), - PJ_EBUSY); - - pj_lock_acquire(ioque->lock); - - key->op |= PJ_IOQUEUE_OP_READ; - key->rd_flags = 0; - key->rd_buf = buffer; - key->rd_buflen = buflen; - - pj_lock_release(ioque->lock); - return PJ_EPENDING; -} - - -/* - * pj_ioqueue_recv() - * - * Start asynchronous recv() from the socket. - */ -PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - void *buffer, - pj_size_t buflen, - unsigned flags ) -{ - PJ_ASSERT_RETURN(ioque && key && buffer, PJ_EINVAL); - PJ_CHECK_STACK(); - - /* For consistency with other ioqueue implementation, we would reject - * if descriptor has already been submitted for reading before. - */ - PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_READ) == 0 && - (key->op & PJ_IOQUEUE_OP_RECV) == 0 && - (key->op & PJ_IOQUEUE_OP_RECV_FROM) == 0), - PJ_EBUSY); - - pj_lock_acquire(ioque->lock); - - key->op |= PJ_IOQUEUE_OP_RECV; - key->rd_buf = buffer; - key->rd_buflen = buflen; - key->rd_flags = flags; - - pj_lock_release(ioque->lock); - return PJ_EPENDING; -} - -/* - * pj_ioqueue_recvfrom() - * - * Start asynchronous recvfrom() from the socket. - */ -PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - void *buffer, - pj_size_t buflen, - unsigned flags, - pj_sockaddr_t *addr, - int *addrlen) -{ - PJ_ASSERT_RETURN(ioque && key && buffer, PJ_EINVAL); - PJ_CHECK_STACK(); - - /* For consistency with other ioqueue implementation, we would reject - * if descriptor has already been submitted for reading before. - */ - PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_READ) == 0 && - (key->op & PJ_IOQUEUE_OP_RECV) == 0 && - (key->op & PJ_IOQUEUE_OP_RECV_FROM) == 0), - PJ_EBUSY); - - pj_lock_acquire(ioque->lock); - - key->op |= PJ_IOQUEUE_OP_RECV_FROM; - key->rd_buf = buffer; - key->rd_buflen = buflen; - key->rd_flags = flags; - key->rmt_addr = addr; - key->rmt_addrlen = addrlen; - - pj_lock_release(ioque->lock); - return PJ_EPENDING; -} - -/* - * pj_ioqueue_write() - * - * Start asynchronous write() to the descriptor. - */ -PJ_DEF(pj_status_t) pj_ioqueue_write( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - const void *data, - pj_size_t datalen) -{ - pj_status_t rc; - pj_ssize_t sent; - - PJ_ASSERT_RETURN(ioque && key && data, PJ_EINVAL); - PJ_CHECK_STACK(); - - /* For consistency with other ioqueue implementation, we would reject - * if descriptor has already been submitted for writing before. - */ - PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_WRITE) == 0 && - (key->op & PJ_IOQUEUE_OP_SEND) == 0 && - (key->op & PJ_IOQUEUE_OP_SEND_TO) == 0), - PJ_EBUSY); - - sent = datalen; - /* sent would be -1 after pj_sock_send() if it returns error. */ - rc = pj_sock_send(key->fd, data, &sent, 0); - if (rc != PJ_SUCCESS && rc != PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) { - return rc; - } - - pj_lock_acquire(ioque->lock); - - key->op |= PJ_IOQUEUE_OP_WRITE; - key->wr_buf = NULL; - key->wr_buflen = datalen; - - pj_lock_release(ioque->lock); - - return PJ_EPENDING; -} - -/* - * pj_ioqueue_send() - * - * Start asynchronous send() to the descriptor. - */ -PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - const void *data, - pj_size_t datalen, - unsigned flags) -{ - pj_status_t rc; - pj_ssize_t sent; - - PJ_ASSERT_RETURN(ioque && key && data, PJ_EINVAL); - PJ_CHECK_STACK(); - - /* For consistency with other ioqueue implementation, we would reject - * if descriptor has already been submitted for writing before. - */ - PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_WRITE) == 0 && - (key->op & PJ_IOQUEUE_OP_SEND) == 0 && - (key->op & PJ_IOQUEUE_OP_SEND_TO) == 0), - PJ_EBUSY); - - sent = datalen; - /* sent would be -1 after pj_sock_send() if it returns error. */ - rc = pj_sock_send(key->fd, data, &sent, flags); - if (rc != PJ_SUCCESS && rc != PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) { - return rc; - } - - pj_lock_acquire(ioque->lock); - - key->op |= PJ_IOQUEUE_OP_SEND; - key->wr_buf = NULL; - key->wr_buflen = datalen; - - pj_lock_release(ioque->lock); - - return PJ_EPENDING; -} - - -/* - * pj_ioqueue_sendto() - * - * Start asynchronous write() to the descriptor. - */ -PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - const void *data, - pj_size_t datalen, - unsigned flags, - const pj_sockaddr_t *addr, - int addrlen) -{ - pj_status_t rc; - pj_ssize_t sent; - - PJ_ASSERT_RETURN(ioque && key && data, PJ_EINVAL); - PJ_CHECK_STACK(); - - /* For consistency with other ioqueue implementation, we would reject - * if descriptor has already been submitted for writing before. - */ - PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_WRITE) == 0 && - (key->op & PJ_IOQUEUE_OP_SEND) == 0 && - (key->op & PJ_IOQUEUE_OP_SEND_TO) == 0), - PJ_EBUSY); - - sent = datalen; - /* sent would be -1 after pj_sock_sendto() if it returns error. */ - rc = pj_sock_sendto(key->fd, data, &sent, flags, addr, addrlen); - if (rc != PJ_SUCCESS && rc != PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) { - return rc; - } - - pj_lock_acquire(ioque->lock); - - key->op |= PJ_IOQUEUE_OP_SEND_TO; - key->wr_buf = NULL; - key->wr_buflen = datalen; - - pj_lock_release(ioque->lock); - return PJ_EPENDING; -} - -#if PJ_HAS_TCP -/* - * Initiate overlapped accept() operation. - */ -PJ_DEF(int) pj_ioqueue_accept( pj_ioqueue_t *ioqueue, - pj_ioqueue_key_t *key, - pj_sock_t *new_sock, - pj_sockaddr_t *local, - pj_sockaddr_t *remote, - int *addrlen) -{ - /* check parameters. All must be specified! */ - pj_assert(ioqueue && key && new_sock); - - /* Server socket must have no other operation! */ - pj_assert(key->op == 0); - - pj_lock_acquire(ioqueue->lock); - - key->op = PJ_IOQUEUE_OP_ACCEPT; - key->accept_fd = new_sock; - key->rmt_addr = remote; - key->rmt_addrlen = addrlen; - key->local_addr = local; - key->local_addrlen = addrlen; /* use same addr. as rmt_addrlen */ - - pj_lock_release(ioqueue->lock); - return PJ_EPENDING; -} - -/* - * Initiate overlapped connect() operation (well, it's non-blocking actually, - * since there's no overlapped version of connect()). - */ -PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue, - pj_ioqueue_key_t *key, - const pj_sockaddr_t *addr, - int addrlen ) -{ - pj_status_t rc; - - /* check parameters. All must be specified! */ - PJ_ASSERT_RETURN(ioqueue && key && addr && addrlen, PJ_EINVAL); - - /* Connecting socket must have no other operation! */ - PJ_ASSERT_RETURN(key->op == 0, PJ_EBUSY); - - rc = pj_sock_connect(key->fd, addr, addrlen); - if (rc == PJ_SUCCESS) { - /* Connected! */ - return PJ_SUCCESS; - } else { - if (rc == PJ_STATUS_FROM_OS(OSERR_EINPROGRESS) || - rc == PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) - { - /* Pending! */ - pj_lock_acquire(ioqueue->lock); - key->op = PJ_IOQUEUE_OP_CONNECT; - pj_lock_release(ioqueue->lock); - return PJ_EPENDING; - } else { - /* Error! */ - return rc; - } - } -} -#endif /* PJ_HAS_TCP */ - +/* $Header: /pjproject-0.3/pjlib/src/pj/ioqueue_epoll.c 4 10/29/05 10:27p Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pj/ioqueue_epoll.c $ + * + * 4 10/29/05 10:27p Bennylp + * Fixed misc warnings. + * + * 3 10/29/05 11:49a Bennylp + * Fixed warnings. + * + * 2 10/29/05 11:31a Bennylp + * Changed accept and lock. + * + * 1 10/17/05 10:49p Bennylp + * Created. + * + */ + +/* + * ioqueue_epoll.c + * + * This is the implementation of IOQueue framework using /dev/epoll + * API in _both_ Linux user-mode and kernel-mode. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(PJ_LINUX_KERNEL) || PJ_LINUX_KERNEL==0 + /* + * Linux user mode + */ +# include +# include +# include + +# define epoll_data data.ptr +# define epoll_data_type void* +# define ioctl_val_type unsigned long* +# define getsockopt_val_ptr int* +# define os_getsockopt getsockopt +# define os_ioctl ioctl +# define os_read read +# define os_close close +# define os_epoll_create epoll_create +# define os_epoll_ctl epoll_ctl +# define os_epoll_wait epoll_wait +#else + /* + * Linux kernel mode. + */ +# include +# include +# if defined(MODVERSIONS) +# include +# endif +# include +# include +# include +# include +# include +# include +# include + enum EPOLL_EVENTS + { + EPOLLIN = 0x001, + EPOLLOUT = 0x004, + EPOLLERR = 0x008, + }; +# define os_epoll_create sys_epoll_create + static int os_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) + { + long rc; + mm_segment_t oldfs = get_fs(); + set_fs(KERNEL_DS); + rc = sys_epoll_ctl(epfd, op, fd, event); + set_fs(oldfs); + if (rc) { + errno = -rc; + return -1; + } else { + return 0; + } + } + static int os_epoll_wait(int epfd, struct epoll_event *events, + int maxevents, int timeout) + { + int count; + mm_segment_t oldfs = get_fs(); + set_fs(KERNEL_DS); + count = sys_epoll_wait(epfd, events, maxevents, timeout); + set_fs(oldfs); + return count; + } +# define os_close sys_close +# define os_getsockopt pj_sock_getsockopt + static int os_read(int fd, void *buf, size_t len) + { + long rc; + mm_segment_t oldfs = get_fs(); + set_fs(KERNEL_DS); + rc = sys_read(fd, buf, len); + set_fs(oldfs); + if (rc) { + errno = -rc; + return -1; + } else { + return 0; + } + } +# define socklen_t unsigned +# define ioctl_val_type unsigned long + int ioctl(int fd, int opt, ioctl_val_type value); + static int os_ioctl(int fd, int opt, ioctl_val_type value) + { + int rc; + mm_segment_t oldfs = get_fs(); + set_fs(KERNEL_DS); + rc = ioctl(fd, opt, value); + set_fs(oldfs); + if (rc < 0) { + errno = -rc; + return rc; + } else + return rc; + } +# define getsockopt_val_ptr char* + +# define epoll_data data +# define epoll_data_type __u32 +#endif + +#define THIS_FILE "ioq_epoll" + +#define PJ_IOQUEUE_IS_READ_OP(op) ((op & PJ_IOQUEUE_OP_READ) || \ + (op & PJ_IOQUEUE_OP_RECV) || \ + (op & PJ_IOQUEUE_OP_RECV_FROM)) +#define PJ_IOQUEUE_IS_WRITE_OP(op) ((op & PJ_IOQUEUE_OP_WRITE) || \ + (op & PJ_IOQUEUE_OP_SEND) || \ + (op & PJ_IOQUEUE_OP_SEND_TO)) + + +#if PJ_HAS_TCP +# define PJ_IOQUEUE_IS_ACCEPT_OP(op) (op & PJ_IOQUEUE_OP_ACCEPT) +# define PJ_IOQUEUE_IS_CONNECT_OP(op) (op & PJ_IOQUEUE_OP_CONNECT) +#else +# define PJ_IOQUEUE_IS_ACCEPT_OP(op) 0 +# define PJ_IOQUEUE_IS_CONNECT_OP(op) 0 +#endif + + +//#define TRACE_(expr) PJ_LOG(3,expr) +#define TRACE_(expr) + + +/* + * This describes each key. + */ +struct pj_ioqueue_key_t +{ + PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t) + pj_sock_t fd; + pj_ioqueue_operation_e op; + void *user_data; + pj_ioqueue_callback cb; + + void *rd_buf; + unsigned rd_flags; + pj_size_t rd_buflen; + void *wr_buf; + pj_size_t wr_buflen; + + pj_sockaddr_t *rmt_addr; + int *rmt_addrlen; + + pj_sockaddr_t *local_addr; + int *local_addrlen; + + pj_sock_t *accept_fd; +}; + +/* + * This describes the I/O queue. + */ +struct pj_ioqueue_t +{ + pj_lock_t *lock; + pj_bool_t auto_delete_lock; + unsigned max, count; + pj_ioqueue_key_t hlist; + int epfd; +}; + +/* + * pj_ioqueue_create() + * + * Create select ioqueue. + */ +PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, + pj_size_t max_fd, + int max_threads, + pj_ioqueue_t **p_ioqueue) +{ + pj_ioqueue_t *ioque; + pj_status_t rc; + + PJ_UNUSED_ARG(max_threads); + + if (max_fd > PJ_IOQUEUE_MAX_HANDLES) { + pj_assert(!"max_fd too large"); + return PJ_EINVAL; + } + + ioque = pj_pool_alloc(pool, sizeof(pj_ioqueue_t)); + ioque->max = max_fd; + ioque->count = 0; + pj_list_init(&ioque->hlist); + + rc = pj_lock_create_recursive_mutex(pool, "ioq%p", &ioque->lock); + if (rc != PJ_SUCCESS) + return rc; + + ioque->auto_delete_lock = PJ_TRUE; + ioque->epfd = os_epoll_create(max_fd); + if (ioque->epfd < 0) { + return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); + } + + PJ_LOG(4, ("pjlib", "select() I/O Queue created (%p)", ioque)); + + *p_ioqueue = ioque; + return PJ_SUCCESS; +} + +/* + * pj_ioqueue_destroy() + * + * Destroy ioqueue. + */ +PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque) +{ + PJ_ASSERT_RETURN(ioque, PJ_EINVAL); + PJ_ASSERT_RETURN(ioque->epfd > 0, PJ_EINVALIDOP); + + pj_lock_acquire(ioque->lock); + os_close(ioque->epfd); + ioque->epfd = 0; + if (ioque->auto_delete_lock) + pj_lock_destroy(ioque->lock); + + return PJ_SUCCESS; +} + +/* + * pj_ioqueue_set_lock() + */ +PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, + pj_lock_t *lock, + pj_bool_t auto_delete ) +{ + PJ_ASSERT_RETURN(ioque && lock, PJ_EINVAL); + + if (ioque->auto_delete_lock) { + pj_lock_destroy(ioque->lock); + } + + ioque->lock = lock; + ioque->auto_delete_lock = auto_delete; + + return PJ_SUCCESS; +} + + +/* + * pj_ioqueue_register_sock() + * + * Register a socket to ioqueue. + */ +PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool, + pj_ioqueue_t *ioque, + pj_sock_t sock, + void *user_data, + const pj_ioqueue_callback *cb, + pj_ioqueue_key_t **p_key) +{ + pj_ioqueue_key_t *key = NULL; + pj_uint32_t value; + struct epoll_event ev; + int status; + pj_status_t rc = PJ_SUCCESS; + + PJ_ASSERT_RETURN(pool && ioque && sock != PJ_INVALID_SOCKET && + cb && p_key, PJ_EINVAL); + + pj_lock_acquire(ioque->lock); + + if (ioque->count >= ioque->max) { + rc = PJ_ETOOMANY; + TRACE_((THIS_FILE, "pj_ioqueue_register_sock error: too many files")); + goto on_return; + } + + /* Set socket to nonblocking. */ + value = 1; + if ((rc=os_ioctl(sock, FIONBIO, (ioctl_val_type)&value))) { + TRACE_((THIS_FILE, "pj_ioqueue_register_sock error: ioctl rc=%d", + rc)); + rc = pj_get_netos_error(); + goto on_return; + } + + /* Create key. */ + key = (pj_ioqueue_key_t*)pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t)); + key->fd = sock; + key->user_data = user_data; + pj_memcpy(&key->cb, cb, sizeof(pj_ioqueue_callback)); + + /* os_epoll_ctl. */ + ev.events = EPOLLIN | EPOLLOUT | EPOLLERR; + ev.epoll_data = (epoll_data_type)key; + status = os_epoll_ctl(ioque->epfd, EPOLL_CTL_ADD, sock, &ev); + if (status < 0) { + rc = pj_get_os_error(); + TRACE_((THIS_FILE, + "pj_ioqueue_register_sock error: os_epoll_ctl rc=%d", + status)); + goto on_return; + } + + /* Register */ + pj_list_insert_before(&ioque->hlist, key); + ++ioque->count; + +on_return: + *p_key = key; + pj_lock_release(ioque->lock); + + return rc; +} + +/* + * pj_ioqueue_unregister() + * + * Unregister handle from ioqueue. + */ +PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key) +{ + struct epoll_event ev; + int status; + + PJ_ASSERT_RETURN(ioque && key, PJ_EINVAL); + + pj_lock_acquire(ioque->lock); + + pj_assert(ioque->count > 0); + --ioque->count; + pj_list_erase(key); + + ev.events = 0; + ev.epoll_data = (epoll_data_type)key; + status = os_epoll_ctl( ioque->epfd, EPOLL_CTL_DEL, key->fd, &ev); + if (status != 0) { + pj_status_t rc = pj_get_os_error(); + pj_lock_release(ioque->lock); + return rc; + } + + pj_lock_release(ioque->lock); + return PJ_SUCCESS; +} + +/* + * pj_ioqueue_get_user_data() + * + * Obtain value associated with a key. + */ +PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key ) +{ + PJ_ASSERT_RETURN(key != NULL, NULL); + return key->user_data; +} + + +/* + * pj_ioqueue_poll() + * + */ +PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout) +{ + int i, count, processed; + struct epoll_event events[16]; + int msec; + + PJ_CHECK_STACK(); + + msec = timeout ? PJ_TIME_VAL_MSEC(*timeout) : 9000; + + count = os_epoll_wait( ioque->epfd, events, PJ_ARRAY_SIZE(events), msec); + if (count <= 0) + return count; + + /* Lock ioqueue. */ + pj_lock_acquire(ioque->lock); + + processed = 0; + + for (i=0; iop))) { + pj_ssize_t bytes_read = h->rd_buflen; + + if ((h->op & PJ_IOQUEUE_OP_RECV_FROM)) { + rc = pj_sock_recvfrom( h->fd, h->rd_buf, &bytes_read, 0, + h->rmt_addr, h->rmt_addrlen); + } else if ((h->op & PJ_IOQUEUE_OP_RECV)) { + rc = pj_sock_recv(h->fd, h->rd_buf, &bytes_read, 0); + } else { + bytes_read = os_read( h->fd, h->rd_buf, bytes_read); + rc = (bytes_read >= 0) ? PJ_SUCCESS : pj_get_os_error(); + } + + if (rc != PJ_SUCCESS) { + bytes_read = -rc; + } + + h->op &= ~(PJ_IOQUEUE_OP_READ | PJ_IOQUEUE_OP_RECV | + PJ_IOQUEUE_OP_RECV_FROM); + + /* Call callback. */ + (*h->cb.on_read_complete)(h, bytes_read); + + ++processed; + } + /* + * Check for completion of accept() operation. + */ + else if ((events[i].events & EPOLLIN) && + (h->op & PJ_IOQUEUE_OP_ACCEPT)) + { + /* accept() must be the only operation specified on + * server socket + */ + pj_assert( h->op == PJ_IOQUEUE_OP_ACCEPT); + + rc = pj_sock_accept( h->fd, h->accept_fd, + h->rmt_addr, h->rmt_addrlen); + if (rc==PJ_SUCCESS && h->local_addr) { + rc = pj_sock_getsockname(*h->accept_fd, h->local_addr, + h->local_addrlen); + } + + h->op &= ~(PJ_IOQUEUE_OP_ACCEPT); + + /* Call callback. */ + (*h->cb.on_accept_complete)(h, *h->accept_fd, rc); + + ++processed; + } + + /* + * Check for completion of write operations. + */ + if ((events[i].events & EPOLLOUT) && PJ_IOQUEUE_IS_WRITE_OP(h->op)) { + /* Completion of write(), send(), or sendto() operation. */ + + /* Clear operation. */ + h->op &= ~(PJ_IOQUEUE_OP_WRITE | PJ_IOQUEUE_OP_SEND | + PJ_IOQUEUE_OP_SEND_TO); + + /* Call callback. */ + /* All data must have been sent? */ + (*h->cb.on_write_complete)(h, h->wr_buflen); + + ++processed; + } +#if PJ_HAS_TCP + /* + * Check for completion of connect() operation. + */ + else if ((events[i].events & EPOLLOUT) && + (h->op & PJ_IOQUEUE_OP_CONNECT)) + { + /* Completion of connect() operation */ + pj_ssize_t bytes_transfered; + + /* from connect(2): + * On Linux, use getsockopt to read the SO_ERROR option at + * level SOL_SOCKET to determine whether connect() completed + * successfully (if SO_ERROR is zero). + */ + int value; + socklen_t vallen = sizeof(value); + int gs_rc = os_getsockopt(h->fd, SOL_SOCKET, SO_ERROR, + (getsockopt_val_ptr)&value, &vallen); + if (gs_rc != 0) { + /* Argh!! What to do now??? + * Just indicate that the socket is connected. The + * application will get error as soon as it tries to use + * the socket to send/receive. + */ + bytes_transfered = 0; + } else { + bytes_transfered = value; + } + + /* Clear operation. */ + h->op &= (~PJ_IOQUEUE_OP_CONNECT); + + /* Call callback. */ + (*h->cb.on_connect_complete)(h, bytes_transfered); + + ++processed; + } +#endif /* PJ_HAS_TCP */ + + /* + * Check for error condition. + */ + if (events[i].events & EPOLLERR) { + if (h->op & PJ_IOQUEUE_OP_CONNECT) { + h->op &= ~PJ_IOQUEUE_OP_CONNECT; + + /* Call callback. */ + (*h->cb.on_connect_complete)(h, -1); + + ++processed; + } + } + } + + pj_lock_release(ioque->lock); + + return processed; +} + +/* + * pj_ioqueue_read() + * + * Start asynchronous read from the descriptor. + */ +PJ_DEF(pj_status_t) pj_ioqueue_read( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + void *buffer, + pj_size_t buflen) +{ + PJ_ASSERT_RETURN(ioque && key && buffer, PJ_EINVAL); + PJ_CHECK_STACK(); + + /* For consistency with other ioqueue implementation, we would reject + * if descriptor has already been submitted for reading before. + */ + PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_READ) == 0 && + (key->op & PJ_IOQUEUE_OP_RECV) == 0 && + (key->op & PJ_IOQUEUE_OP_RECV_FROM) == 0), + PJ_EBUSY); + + pj_lock_acquire(ioque->lock); + + key->op |= PJ_IOQUEUE_OP_READ; + key->rd_flags = 0; + key->rd_buf = buffer; + key->rd_buflen = buflen; + + pj_lock_release(ioque->lock); + return PJ_EPENDING; +} + + +/* + * pj_ioqueue_recv() + * + * Start asynchronous recv() from the socket. + */ +PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + void *buffer, + pj_size_t buflen, + unsigned flags ) +{ + PJ_ASSERT_RETURN(ioque && key && buffer, PJ_EINVAL); + PJ_CHECK_STACK(); + + /* For consistency with other ioqueue implementation, we would reject + * if descriptor has already been submitted for reading before. + */ + PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_READ) == 0 && + (key->op & PJ_IOQUEUE_OP_RECV) == 0 && + (key->op & PJ_IOQUEUE_OP_RECV_FROM) == 0), + PJ_EBUSY); + + pj_lock_acquire(ioque->lock); + + key->op |= PJ_IOQUEUE_OP_RECV; + key->rd_buf = buffer; + key->rd_buflen = buflen; + key->rd_flags = flags; + + pj_lock_release(ioque->lock); + return PJ_EPENDING; +} + +/* + * pj_ioqueue_recvfrom() + * + * Start asynchronous recvfrom() from the socket. + */ +PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + void *buffer, + pj_size_t buflen, + unsigned flags, + pj_sockaddr_t *addr, + int *addrlen) +{ + PJ_ASSERT_RETURN(ioque && key && buffer, PJ_EINVAL); + PJ_CHECK_STACK(); + + /* For consistency with other ioqueue implementation, we would reject + * if descriptor has already been submitted for reading before. + */ + PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_READ) == 0 && + (key->op & PJ_IOQUEUE_OP_RECV) == 0 && + (key->op & PJ_IOQUEUE_OP_RECV_FROM) == 0), + PJ_EBUSY); + + pj_lock_acquire(ioque->lock); + + key->op |= PJ_IOQUEUE_OP_RECV_FROM; + key->rd_buf = buffer; + key->rd_buflen = buflen; + key->rd_flags = flags; + key->rmt_addr = addr; + key->rmt_addrlen = addrlen; + + pj_lock_release(ioque->lock); + return PJ_EPENDING; +} + +/* + * pj_ioqueue_write() + * + * Start asynchronous write() to the descriptor. + */ +PJ_DEF(pj_status_t) pj_ioqueue_write( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + const void *data, + pj_size_t datalen) +{ + pj_status_t rc; + pj_ssize_t sent; + + PJ_ASSERT_RETURN(ioque && key && data, PJ_EINVAL); + PJ_CHECK_STACK(); + + /* For consistency with other ioqueue implementation, we would reject + * if descriptor has already been submitted for writing before. + */ + PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_WRITE) == 0 && + (key->op & PJ_IOQUEUE_OP_SEND) == 0 && + (key->op & PJ_IOQUEUE_OP_SEND_TO) == 0), + PJ_EBUSY); + + sent = datalen; + /* sent would be -1 after pj_sock_send() if it returns error. */ + rc = pj_sock_send(key->fd, data, &sent, 0); + if (rc != PJ_SUCCESS && rc != PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) { + return rc; + } + + pj_lock_acquire(ioque->lock); + + key->op |= PJ_IOQUEUE_OP_WRITE; + key->wr_buf = NULL; + key->wr_buflen = datalen; + + pj_lock_release(ioque->lock); + + return PJ_EPENDING; +} + +/* + * pj_ioqueue_send() + * + * Start asynchronous send() to the descriptor. + */ +PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + const void *data, + pj_size_t datalen, + unsigned flags) +{ + pj_status_t rc; + pj_ssize_t sent; + + PJ_ASSERT_RETURN(ioque && key && data, PJ_EINVAL); + PJ_CHECK_STACK(); + + /* For consistency with other ioqueue implementation, we would reject + * if descriptor has already been submitted for writing before. + */ + PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_WRITE) == 0 && + (key->op & PJ_IOQUEUE_OP_SEND) == 0 && + (key->op & PJ_IOQUEUE_OP_SEND_TO) == 0), + PJ_EBUSY); + + sent = datalen; + /* sent would be -1 after pj_sock_send() if it returns error. */ + rc = pj_sock_send(key->fd, data, &sent, flags); + if (rc != PJ_SUCCESS && rc != PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) { + return rc; + } + + pj_lock_acquire(ioque->lock); + + key->op |= PJ_IOQUEUE_OP_SEND; + key->wr_buf = NULL; + key->wr_buflen = datalen; + + pj_lock_release(ioque->lock); + + return PJ_EPENDING; +} + + +/* + * pj_ioqueue_sendto() + * + * Start asynchronous write() to the descriptor. + */ +PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + const void *data, + pj_size_t datalen, + unsigned flags, + const pj_sockaddr_t *addr, + int addrlen) +{ + pj_status_t rc; + pj_ssize_t sent; + + PJ_ASSERT_RETURN(ioque && key && data, PJ_EINVAL); + PJ_CHECK_STACK(); + + /* For consistency with other ioqueue implementation, we would reject + * if descriptor has already been submitted for writing before. + */ + PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_WRITE) == 0 && + (key->op & PJ_IOQUEUE_OP_SEND) == 0 && + (key->op & PJ_IOQUEUE_OP_SEND_TO) == 0), + PJ_EBUSY); + + sent = datalen; + /* sent would be -1 after pj_sock_sendto() if it returns error. */ + rc = pj_sock_sendto(key->fd, data, &sent, flags, addr, addrlen); + if (rc != PJ_SUCCESS && rc != PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) { + return rc; + } + + pj_lock_acquire(ioque->lock); + + key->op |= PJ_IOQUEUE_OP_SEND_TO; + key->wr_buf = NULL; + key->wr_buflen = datalen; + + pj_lock_release(ioque->lock); + return PJ_EPENDING; +} + +#if PJ_HAS_TCP +/* + * Initiate overlapped accept() operation. + */ +PJ_DEF(int) pj_ioqueue_accept( pj_ioqueue_t *ioqueue, + pj_ioqueue_key_t *key, + pj_sock_t *new_sock, + pj_sockaddr_t *local, + pj_sockaddr_t *remote, + int *addrlen) +{ + /* check parameters. All must be specified! */ + pj_assert(ioqueue && key && new_sock); + + /* Server socket must have no other operation! */ + pj_assert(key->op == 0); + + pj_lock_acquire(ioqueue->lock); + + key->op = PJ_IOQUEUE_OP_ACCEPT; + key->accept_fd = new_sock; + key->rmt_addr = remote; + key->rmt_addrlen = addrlen; + key->local_addr = local; + key->local_addrlen = addrlen; /* use same addr. as rmt_addrlen */ + + pj_lock_release(ioqueue->lock); + return PJ_EPENDING; +} + +/* + * Initiate overlapped connect() operation (well, it's non-blocking actually, + * since there's no overlapped version of connect()). + */ +PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue, + pj_ioqueue_key_t *key, + const pj_sockaddr_t *addr, + int addrlen ) +{ + pj_status_t rc; + + /* check parameters. All must be specified! */ + PJ_ASSERT_RETURN(ioqueue && key && addr && addrlen, PJ_EINVAL); + + /* Connecting socket must have no other operation! */ + PJ_ASSERT_RETURN(key->op == 0, PJ_EBUSY); + + rc = pj_sock_connect(key->fd, addr, addrlen); + if (rc == PJ_SUCCESS) { + /* Connected! */ + return PJ_SUCCESS; + } else { + if (rc == PJ_STATUS_FROM_OS(OSERR_EINPROGRESS) || + rc == PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) + { + /* Pending! */ + pj_lock_acquire(ioqueue->lock); + key->op = PJ_IOQUEUE_OP_CONNECT; + pj_lock_release(ioqueue->lock); + return PJ_EPENDING; + } else { + /* Error! */ + return rc; + } + } +} +#endif /* PJ_HAS_TCP */ + diff --git a/pjlib/src/pj/ioqueue_linux_kernel.c b/pjlib/src/pj/ioqueue_linux_kernel.c index b8338118..debf2cbd 100644 --- a/pjlib/src/pj/ioqueue_linux_kernel.c +++ b/pjlib/src/pj/ioqueue_linux_kernel.c @@ -1,150 +1,150 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/ioqueue_linux_kernel.c 1 10/05/05 4:42p Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/ioqueue_linux_kernel.c $ - * - * 1 10/05/05 4:42p Bennylp - * Created. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#define THIS_FILE "ioqueue" - -#define PJ_IOQUEUE_IS_READ_OP(op) \ - ((op & PJ_IOQUEUE_OP_READ) || (op & PJ_IOQUEUE_OP_RECV_FROM)) -#define PJ_IOQUEUE_IS_WRITE_OP(op) \ - ((op & PJ_IOQUEUE_OP_WRITE) || (op & PJ_IOQUEUE_OP_SEND_TO)) - - -#if PJ_HAS_TCP -# define PJ_IOQUEUE_IS_ACCEPT_OP(op) (op & PJ_IOQUEUE_OP_ACCEPT) -# define PJ_IOQUEUE_IS_CONNECT_OP(op) (op & PJ_IOQUEUE_OP_CONNECT) -#else -# define PJ_IOQUEUE_IS_ACCEPT_OP(op) 0 -# define PJ_IOQUEUE_IS_CONNECT_OP(op) 0 -#endif - -#if defined(PJ_DEBUG) && PJ_DEBUG != 0 -# define VALIDATE_FD_SET 1 -#else -# define VALIDATE_FD_SET 0 -#endif - -struct pj_ioqueue_key_t -{ - PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t) - pj_sock_t fd; - pj_ioqueue_operation_e op; - void *user_data; - pj_ioqueue_callback cb; -}; - -struct pj_ioqueue_t -{ -}; - -PJ_DEF(pj_ioqueue_t*) pj_ioqueue_create(pj_pool_t *pool, pj_size_t max_fd) -{ - return NULL; -} - -PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque) -{ - return 0; -} - -PJ_DEF(pj_ioqueue_key_t*) pj_ioqueue_register( pj_pool_t *pool, - pj_ioqueue_t *ioque, - pj_oshandle_t sock, - void *user_data, - const pj_ioqueue_callback *cb) -{ - return NULL; -} - -PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key) -{ - return -1; -} - -PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key ) -{ - return NULL; -} - - -PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout) -{ - return -1; -} - -PJ_DEF(int) pj_ioqueue_read( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - void *buffer, - pj_size_t buflen) -{ - return -1; -} - -PJ_DEF(int) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - void *buffer, - pj_size_t buflen, - pj_sockaddr_t *addr, - int *addrlen) -{ - return -1; -} - -PJ_DEF(int) pj_ioqueue_write( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - const void *data, - pj_size_t datalen) -{ - return -1; -} - -PJ_DEF(int) pj_ioqueue_sendto( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - const void *data, - pj_size_t datalen, - const pj_sockaddr_t *addr, - int addrlen) -{ - return -1; -} - -#if PJ_HAS_TCP -/* - * Initiate overlapped accept() operation. - */ -PJ_DEF(int) pj_ioqueue_accept( pj_ioqueue_t *ioqueue, - pj_ioqueue_key_t *key, - pj_sock_t *new_sock, - pj_sockaddr_t *local, - pj_sockaddr_t *remote, - int *addrlen) -{ - return -1; -} - -/* - * Initiate overlapped connect() operation (well, it's non-blocking actually, - * since there's no overlapped version of connect()). - */ -PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue, - pj_ioqueue_key_t *key, - const pj_sockaddr_t *addr, - int addrlen ) -{ - return -1; -} -#endif /* PJ_HAS_TCP */ - +/* $Header: /pjproject-0.3/pjlib/src/pj/ioqueue_linux_kernel.c 1 10/05/05 4:42p Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/ioqueue_linux_kernel.c $ + * + * 1 10/05/05 4:42p Bennylp + * Created. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define THIS_FILE "ioqueue" + +#define PJ_IOQUEUE_IS_READ_OP(op) \ + ((op & PJ_IOQUEUE_OP_READ) || (op & PJ_IOQUEUE_OP_RECV_FROM)) +#define PJ_IOQUEUE_IS_WRITE_OP(op) \ + ((op & PJ_IOQUEUE_OP_WRITE) || (op & PJ_IOQUEUE_OP_SEND_TO)) + + +#if PJ_HAS_TCP +# define PJ_IOQUEUE_IS_ACCEPT_OP(op) (op & PJ_IOQUEUE_OP_ACCEPT) +# define PJ_IOQUEUE_IS_CONNECT_OP(op) (op & PJ_IOQUEUE_OP_CONNECT) +#else +# define PJ_IOQUEUE_IS_ACCEPT_OP(op) 0 +# define PJ_IOQUEUE_IS_CONNECT_OP(op) 0 +#endif + +#if defined(PJ_DEBUG) && PJ_DEBUG != 0 +# define VALIDATE_FD_SET 1 +#else +# define VALIDATE_FD_SET 0 +#endif + +struct pj_ioqueue_key_t +{ + PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t) + pj_sock_t fd; + pj_ioqueue_operation_e op; + void *user_data; + pj_ioqueue_callback cb; +}; + +struct pj_ioqueue_t +{ +}; + +PJ_DEF(pj_ioqueue_t*) pj_ioqueue_create(pj_pool_t *pool, pj_size_t max_fd) +{ + return NULL; +} + +PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque) +{ + return 0; +} + +PJ_DEF(pj_ioqueue_key_t*) pj_ioqueue_register( pj_pool_t *pool, + pj_ioqueue_t *ioque, + pj_oshandle_t sock, + void *user_data, + const pj_ioqueue_callback *cb) +{ + return NULL; +} + +PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key) +{ + return -1; +} + +PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key ) +{ + return NULL; +} + + +PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout) +{ + return -1; +} + +PJ_DEF(int) pj_ioqueue_read( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + void *buffer, + pj_size_t buflen) +{ + return -1; +} + +PJ_DEF(int) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + void *buffer, + pj_size_t buflen, + pj_sockaddr_t *addr, + int *addrlen) +{ + return -1; +} + +PJ_DEF(int) pj_ioqueue_write( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + const void *data, + pj_size_t datalen) +{ + return -1; +} + +PJ_DEF(int) pj_ioqueue_sendto( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + const void *data, + pj_size_t datalen, + const pj_sockaddr_t *addr, + int addrlen) +{ + return -1; +} + +#if PJ_HAS_TCP +/* + * Initiate overlapped accept() operation. + */ +PJ_DEF(int) pj_ioqueue_accept( pj_ioqueue_t *ioqueue, + pj_ioqueue_key_t *key, + pj_sock_t *new_sock, + pj_sockaddr_t *local, + pj_sockaddr_t *remote, + int *addrlen) +{ + return -1; +} + +/* + * Initiate overlapped connect() operation (well, it's non-blocking actually, + * since there's no overlapped version of connect()). + */ +PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue, + pj_ioqueue_key_t *key, + const pj_sockaddr_t *addr, + int addrlen ) +{ + return -1; +} +#endif /* PJ_HAS_TCP */ + diff --git a/pjlib/src/pj/ioqueue_select.c b/pjlib/src/pj/ioqueue_select.c index 615c758e..a16aba2d 100644 --- a/pjlib/src/pj/ioqueue_select.c +++ b/pjlib/src/pj/ioqueue_select.c @@ -1,947 +1,964 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/ioqueue_select.c 15 10/29/05 10:27p Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/ioqueue_select.c $ - * - * 15 10/29/05 10:27p Bennylp - * Fixed misc warnings. - * - * 14 10/29/05 11:31a Bennylp - * Changed accept and lock. - * - * 13 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 12 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 11 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ - -/* - * sock_select.c - * - * This is the implementation of IOQueue using pj_sock_select(). - * It runs anywhere where pj_sock_select() is available (currently - * Win32, Linux, Linux kernel, etc.). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * ISSUES with ioqueue_select() - * - * EAGAIN/EWOULDBLOCK error in recv(): - * - when multiple threads are working with the ioqueue, application - * may receive EAGAIN or EWOULDBLOCK in the receive callback. - * This error happens because more than one thread is watching for - * the same descriptor set, so when all of them call recv() or recvfrom() - * simultaneously, only one will succeed and the rest will get the error. - * - */ -#define THIS_FILE "ioq_select" - -#define PJ_IOQUEUE_IS_READ_OP(op) ((op & PJ_IOQUEUE_OP_READ) || \ - (op & PJ_IOQUEUE_OP_RECV) || \ - (op & PJ_IOQUEUE_OP_RECV_FROM)) -#define PJ_IOQUEUE_IS_WRITE_OP(op) ((op & PJ_IOQUEUE_OP_WRITE) || \ - (op & PJ_IOQUEUE_OP_SEND) || \ - (op & PJ_IOQUEUE_OP_SEND_TO)) - - -#if PJ_HAS_TCP -# define PJ_IOQUEUE_IS_ACCEPT_OP(op) (op & PJ_IOQUEUE_OP_ACCEPT) -# define PJ_IOQUEUE_IS_CONNECT_OP(op) (op & PJ_IOQUEUE_OP_CONNECT) -#else -# define PJ_IOQUEUE_IS_ACCEPT_OP(op) 0 -# define PJ_IOQUEUE_IS_CONNECT_OP(op) 0 -#endif - -/* - * During debugging build, VALIDATE_FD_SET is set. - * This will check the validity of the fd_sets. - */ -#if defined(PJ_DEBUG) && PJ_DEBUG != 0 -# define VALIDATE_FD_SET 1 -#else -# define VALIDATE_FD_SET 0 -#endif - -/* - * This describes each key. - */ -struct pj_ioqueue_key_t -{ - PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t) - pj_sock_t fd; - pj_ioqueue_operation_e op; - void *user_data; - pj_ioqueue_callback cb; - - void *rd_buf; - unsigned rd_flags; - pj_size_t rd_buflen; - void *wr_buf; - pj_size_t wr_buflen; - - pj_sockaddr_t *rmt_addr; - int *rmt_addrlen; - - pj_sockaddr_t *local_addr; - int *local_addrlen; - - pj_sock_t *accept_fd; -}; - -/* - * This describes the I/O queue itself. - */ -struct pj_ioqueue_t -{ - pj_lock_t *lock; - pj_bool_t auto_delete_lock; - unsigned max, count; - pj_ioqueue_key_t hlist; - pj_fd_set_t rfdset; - pj_fd_set_t wfdset; -#if PJ_HAS_TCP - pj_fd_set_t xfdset; -#endif -}; - -/* - * pj_ioqueue_create() - * - * Create select ioqueue. - */ -PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, - pj_size_t max_fd, - int max_threads, - pj_ioqueue_t **p_ioqueue) -{ - pj_ioqueue_t *ioque; - pj_status_t rc; - - PJ_UNUSED_ARG(max_threads); - - if (max_fd > PJ_IOQUEUE_MAX_HANDLES) { - pj_assert(!"max_fd too large"); - return PJ_EINVAL; - } - - ioque = pj_pool_alloc(pool, sizeof(pj_ioqueue_t)); - ioque->max = max_fd; - ioque->count = 0; - PJ_FD_ZERO(&ioque->rfdset); - PJ_FD_ZERO(&ioque->wfdset); -#if PJ_HAS_TCP - PJ_FD_ZERO(&ioque->xfdset); -#endif - pj_list_init(&ioque->hlist); - - rc = pj_lock_create_recursive_mutex(pool, "ioq%p", &ioque->lock); - if (rc != PJ_SUCCESS) - return rc; - - ioque->auto_delete_lock = PJ_TRUE; - - PJ_LOG(4, ("pjlib", "select() I/O Queue created (%p)", ioque)); - - *p_ioqueue = ioque; - return PJ_SUCCESS; -} - -/* - * pj_ioqueue_destroy() - * - * Destroy ioqueue. - */ -PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque) -{ - pj_status_t rc = PJ_SUCCESS; - - PJ_ASSERT_RETURN(ioque, PJ_EINVAL); - - if (ioque->auto_delete_lock) - rc = pj_lock_destroy(ioque->lock); - - return rc; -} - - -/* - * pj_ioqueue_set_lock() - */ -PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, - pj_lock_t *lock, - pj_bool_t auto_delete ) -{ - PJ_ASSERT_RETURN(ioque && lock, PJ_EINVAL); - - if (ioque->auto_delete_lock) { - pj_lock_destroy(ioque->lock); - } - - ioque->lock = lock; - ioque->auto_delete_lock = auto_delete; - - return PJ_SUCCESS; -} - - -/* - * pj_ioqueue_register_sock() - * - * Register a handle to ioqueue. - */ -PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool, - pj_ioqueue_t *ioque, - pj_sock_t sock, - void *user_data, - const pj_ioqueue_callback *cb, - pj_ioqueue_key_t **p_key) -{ - pj_ioqueue_key_t *key = NULL; - pj_uint32_t value; - pj_status_t rc = PJ_SUCCESS; - - PJ_ASSERT_RETURN(pool && ioque && sock != PJ_INVALID_SOCKET && - cb && p_key, PJ_EINVAL); - - pj_lock_acquire(ioque->lock); - - if (ioque->count >= ioque->max) { - rc = PJ_ETOOMANY; - goto on_return; - } - - /* Set socket to nonblocking. */ - value = 1; -#ifdef PJ_WIN32 - if (ioctlsocket(sock, FIONBIO, (unsigned long*)&value)) { -#else - if (ioctl(sock, FIONBIO, &value)) { -#endif - rc = pj_get_netos_error(); - goto on_return; - } - - /* Create key. */ - key = (pj_ioqueue_key_t*)pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t)); - key->fd = sock; - key->user_data = user_data; - - /* Save callback. */ - pj_memcpy(&key->cb, cb, sizeof(pj_ioqueue_callback)); - - /* Register */ - pj_list_insert_before(&ioque->hlist, key); - ++ioque->count; - -on_return: - *p_key = key; - pj_lock_release(ioque->lock); - - return rc; -} - -/* - * pj_ioqueue_unregister() - * - * Unregister handle from ioqueue. - */ -PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key) -{ - PJ_ASSERT_RETURN(ioque && key, PJ_EINVAL); - - pj_lock_acquire(ioque->lock); - - pj_assert(ioque->count > 0); - --ioque->count; - pj_list_erase(key); - PJ_FD_CLR(key->fd, &ioque->rfdset); - PJ_FD_CLR(key->fd, &ioque->wfdset); -#if PJ_HAS_TCP - PJ_FD_CLR(key->fd, &ioque->xfdset); -#endif - - pj_lock_release(ioque->lock); - return PJ_SUCCESS; -} - -/* - * pj_ioqueue_get_user_data() - * - * Obtain value associated with a key. - */ -PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key ) -{ - PJ_ASSERT_RETURN(key != NULL, NULL); - return key->user_data; -} - - -/* This supposed to check whether the fd_set values are consistent - * with the operation currently set in each key. - */ -#if VALIDATE_FD_SET -static void validate_sets(const pj_ioqueue_t *ioque, - const pj_fd_set_t *rfdset, - const pj_fd_set_t *wfdset, - const pj_fd_set_t *xfdset) -{ - pj_ioqueue_key_t *key; - - key = ioque->hlist.next; - while (key != &ioque->hlist) { - if ((key->op & PJ_IOQUEUE_OP_READ) - || (key->op & PJ_IOQUEUE_OP_RECV) - || (key->op & PJ_IOQUEUE_OP_RECV_FROM) -#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 - || (key->op & PJ_IOQUEUE_OP_ACCEPT) -#endif - ) - { - pj_assert(PJ_FD_ISSET(key->fd, rfdset)); - } - else { - pj_assert(PJ_FD_ISSET(key->fd, rfdset) == 0); - } - if ((key->op & PJ_IOQUEUE_OP_WRITE) - || (key->op & PJ_IOQUEUE_OP_SEND) - || (key->op & PJ_IOQUEUE_OP_SEND_TO) -#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 - || (key->op & PJ_IOQUEUE_OP_CONNECT) -#endif - ) - { - pj_assert(PJ_FD_ISSET(key->fd, wfdset)); - } - else { - pj_assert(PJ_FD_ISSET(key->fd, wfdset) == 0); - } -#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 - if (key->op & PJ_IOQUEUE_OP_CONNECT) - { - pj_assert(PJ_FD_ISSET(key->fd, xfdset)); - } - else { - pj_assert(PJ_FD_ISSET(key->fd, xfdset) == 0); - } -#endif /* PJ_HAS_TCP */ - - key = key->next; - } -} -#endif /* VALIDATE_FD_SET */ - - -/* - * pj_ioqueue_poll() - * - * Few things worth written: - * - * - we used to do only one callback called per poll, but it didn't go - * very well. The reason is because on some situation, the write - * callback gets called all the time, thus doesn't give the read - * callback to get called. This happens, for example, when user - * submit write operation inside the write callback. - * As the result, we changed the behaviour so that now multiple - * callbacks are called in a single poll. It should be fast too, - * just that we need to be carefull with the ioqueue data structs. - * - * - to guarantee preemptiveness etc, the poll function must strictly - * work on fd_set copy of the ioqueue (not the original one). - */ -PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout) -{ - pj_fd_set_t rfdset, wfdset, xfdset; - int count; - pj_ioqueue_key_t *h; - - /* Lock ioqueue before making fd_set copies */ - pj_lock_acquire(ioque->lock); - - if (PJ_FD_COUNT(&ioque->rfdset)==0 && - PJ_FD_COUNT(&ioque->wfdset)==0 && - PJ_FD_COUNT(&ioque->xfdset)==0) - { - pj_lock_release(ioque->lock); - if (timeout) - pj_thread_sleep(PJ_TIME_VAL_MSEC(*timeout)); - return 0; - } - - /* Copy ioqueue's pj_fd_set_t to local variables. */ - pj_memcpy(&rfdset, &ioque->rfdset, sizeof(pj_fd_set_t)); - pj_memcpy(&wfdset, &ioque->wfdset, sizeof(pj_fd_set_t)); -#if PJ_HAS_TCP - pj_memcpy(&xfdset, &ioque->xfdset, sizeof(pj_fd_set_t)); -#else - PJ_FD_ZERO(&xfdset); -#endif - -#if VALIDATE_FD_SET - validate_sets(ioque, &rfdset, &wfdset, &xfdset); -#endif - - /* Unlock ioqueue before select(). */ - pj_lock_release(ioque->lock); - - count = pj_sock_select(FD_SETSIZE, &rfdset, &wfdset, &xfdset, timeout); - - if (count <= 0) - return count; - - /* Lock ioqueue again before scanning for signalled sockets. */ - pj_lock_acquire(ioque->lock); - -#if PJ_HAS_TCP - /* Scan for exception socket */ - h = ioque->hlist.next; -do_except_scan: - for ( ; h!=&ioque->hlist; h = h->next) { - if ((h->op & PJ_IOQUEUE_OP_CONNECT) && PJ_FD_ISSET(h->fd, &xfdset)) - break; - } - if (h != &ioque->hlist) { - /* 'connect()' should be the only operation. */ - pj_assert((h->op == PJ_IOQUEUE_OP_CONNECT)); - - /* Clear operation. */ - h->op &= ~(PJ_IOQUEUE_OP_CONNECT); - PJ_FD_CLR(h->fd, &ioque->wfdset); - PJ_FD_CLR(h->fd, &ioque->xfdset); - PJ_FD_CLR(h->fd, &wfdset); - PJ_FD_CLR(h->fd, &xfdset); - - /* Call callback. */ - if (h->cb.on_connect_complete) - (*h->cb.on_connect_complete)(h, -1); - - /* Re-scan exception list. */ - goto do_except_scan; - } -#endif /* PJ_HAS_TCP */ - - /* Scan for readable socket. */ - h = ioque->hlist.next; -do_readable_scan: - for ( ; h!=&ioque->hlist; h = h->next) { - if ((PJ_IOQUEUE_IS_READ_OP(h->op) || PJ_IOQUEUE_IS_ACCEPT_OP(h->op)) && - PJ_FD_ISSET(h->fd, &rfdset)) - { - break; - } - } - if (h != &ioque->hlist) { - pj_status_t rc; - - pj_assert(PJ_IOQUEUE_IS_READ_OP(h->op) || - PJ_IOQUEUE_IS_ACCEPT_OP(h->op)); - -# if PJ_HAS_TCP - if ((h->op & PJ_IOQUEUE_OP_ACCEPT)) { - /* accept() must be the only operation specified on server socket */ - pj_assert(h->op == PJ_IOQUEUE_OP_ACCEPT); - - rc=pj_sock_accept(h->fd, h->accept_fd, h->rmt_addr, h->rmt_addrlen); - if (rc==0 && h->local_addr) { - rc = pj_sock_getsockname(*h->accept_fd, h->local_addr, - h->local_addrlen); - } - - h->op &= ~(PJ_IOQUEUE_OP_ACCEPT); - PJ_FD_CLR(h->fd, &ioque->rfdset); - - /* Call callback. */ - if (h->cb.on_accept_complete) - (*h->cb.on_accept_complete)(h, *h->accept_fd, rc); - - /* Re-scan readable sockets. */ - goto do_readable_scan; - } - else { -# endif - pj_ssize_t bytes_read = h->rd_buflen; - - if ((h->op & PJ_IOQUEUE_OP_RECV_FROM)) { - rc = pj_sock_recvfrom(h->fd, h->rd_buf, &bytes_read, 0, - h->rmt_addr, h->rmt_addrlen); - } else if ((h->op & PJ_IOQUEUE_OP_RECV)) { - rc = pj_sock_recv(h->fd, h->rd_buf, &bytes_read, 0); - } else { - /* - * User has specified pj_ioqueue_read(). - * On Win32, we should do ReadFile(). But because we got - * here because of select() anyway, user must have put a - * socket descriptor on h->fd, which in this case we can - * just call pj_sock_recv() instead of ReadFile(). - * On Unix, user may put a file in h->fd, so we'll have - * to call read() here. - * This may not compile on systems which doesn't have - * read(). That's why we only specify PJ_LINUX here so - * that error is easier to catch. - */ -# if defined(PJ_WIN32) && PJ_WIN32 != 0 - rc = pj_sock_recv(h->fd, h->rd_buf, &bytes_read, 0); -# elif defined(PJ_LINUX) && PJ_LINUX != 0 - bytes_read = read(h->fd, h->rd_buf, bytes_read); - rc = (bytes_read >= 0) ? PJ_SUCCESS : pj_get_os_error(); -# elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0 - bytes_read = sys_read(h->fd, h->rd_buf, bytes_read); - rc = (bytes_read >= 0) ? PJ_SUCCESS : -bytes_read; -# else -# error "Check this man!" -# endif - } - - if (rc != PJ_SUCCESS) { -# if defined(PJ_WIN32) && PJ_WIN32 != 0 - /* On Win32, for UDP, WSAECONNRESET on the receive side - * indicates that previous sending has triggered ICMP Port - * Unreachable message. - * But we wouldn't know at this point which one of previous - * key that has triggered the error, since UDP socket can - * be shared! - * So we'll just ignore it! - */ - - if (rc == PJ_STATUS_FROM_OS(WSAECONNRESET)) { - PJ_LOG(4,(THIS_FILE, - "Ignored ICMP port unreach. on key=%p", h)); - } -# endif - - /* In any case we would report this to caller. */ - bytes_read = -rc; - } - - h->op &= ~(PJ_IOQUEUE_OP_READ | PJ_IOQUEUE_OP_RECV | - PJ_IOQUEUE_OP_RECV_FROM); - PJ_FD_CLR(h->fd, &ioque->rfdset); - PJ_FD_CLR(h->fd, &rfdset); - - /* Call callback. */ - if (h->cb.on_read_complete) - (*h->cb.on_read_complete)(h, bytes_read); - - /* Re-scan readable sockets. */ - goto do_readable_scan; - - } - } - - /* Scan for writable socket */ - h = ioque->hlist.next; -do_writable_scan: - for ( ; h!=&ioque->hlist; h = h->next) { - if ((PJ_IOQUEUE_IS_WRITE_OP(h->op) || PJ_IOQUEUE_IS_CONNECT_OP(h->op)) - && PJ_FD_ISSET(h->fd, &wfdset)) - { - break; - } - } - if (h != &ioque->hlist) { - pj_assert(PJ_IOQUEUE_IS_WRITE_OP(h->op) || - PJ_IOQUEUE_IS_CONNECT_OP(h->op)); - -#if PJ_HAS_TCP - if ((h->op & PJ_IOQUEUE_OP_CONNECT)) { - /* Completion of connect() operation */ - pj_ssize_t bytes_transfered; - -#if defined(PJ_LINUX) || defined(PJ_LINUX_KERNEL) - /* from connect(2): - * On Linux, use getsockopt to read the SO_ERROR option at - * level SOL_SOCKET to determine whether connect() completed - * successfully (if SO_ERROR is zero). - */ - int value; - socklen_t vallen = sizeof(value); - int gs_rc = getsockopt(h->fd, SOL_SOCKET, SO_ERROR, - &value, &vallen); - if (gs_rc != 0) { - /* Argh!! What to do now??? - * Just indicate that the socket is connected. The - * application will get error as soon as it tries to use - * the socket to send/receive. - */ - bytes_transfered = 0; - } else { - bytes_transfered = value; - } -#elif defined(PJ_WIN32) - bytes_transfered = 0; /* success */ -#else -# error "Got to check this one!" -#endif - - /* Clear operation. */ - h->op &= (~PJ_IOQUEUE_OP_CONNECT); - PJ_FD_CLR(h->fd, &ioque->wfdset); - PJ_FD_CLR(h->fd, &ioque->xfdset); - - /* Call callback. */ - if (h->cb.on_connect_complete) - (*h->cb.on_connect_complete)(h, bytes_transfered); - - /* Re-scan writable sockets. */ - goto do_writable_scan; - - } else -#endif /* PJ_HAS_TCP */ - { - /* Completion of write(), send(), or sendto() operation. */ - - /* Clear operation. */ - h->op &= ~(PJ_IOQUEUE_OP_WRITE | PJ_IOQUEUE_OP_SEND | - PJ_IOQUEUE_OP_SEND_TO); - PJ_FD_CLR(h->fd, &ioque->wfdset); - PJ_FD_CLR(h->fd, &wfdset); - - /* Call callback. */ - /* All data must have been sent? */ - if (h->cb.on_write_complete) - (*h->cb.on_write_complete)(h, h->wr_buflen); - - /* Re-scan writable sockets. */ - goto do_writable_scan; - } - } - - /* Shouldn't happen. */ - /* For strange reason on WinXP select() can return 1 while there is no - * pj_fd_set_t signaled. */ - /* pj_assert(0); */ - - //count = 0; - - pj_lock_release(ioque->lock); - return count; -} - -/* - * pj_ioqueue_read() - * - * Start asynchronous read from the descriptor. - */ -PJ_DEF(pj_status_t) pj_ioqueue_read( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - void *buffer, - pj_size_t buflen) -{ - PJ_ASSERT_RETURN(ioque && key && buffer, PJ_EINVAL); - PJ_CHECK_STACK(); - - /* For consistency with other ioqueue implementation, we would reject - * if descriptor has already been submitted for reading before. - */ - PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_READ) == 0 && - (key->op & PJ_IOQUEUE_OP_RECV) == 0 && - (key->op & PJ_IOQUEUE_OP_RECV_FROM) == 0), - PJ_EBUSY); - - pj_lock_acquire(ioque->lock); - - key->op |= PJ_IOQUEUE_OP_READ; - key->rd_flags = 0; - key->rd_buf = buffer; - key->rd_buflen = buflen; - PJ_FD_SET(key->fd, &ioque->rfdset); - - pj_lock_release(ioque->lock); - return PJ_EPENDING; -} - - -/* - * pj_ioqueue_recv() - * - * Start asynchronous recv() from the socket. - */ -PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - void *buffer, - pj_size_t buflen, - unsigned flags ) -{ - PJ_ASSERT_RETURN(ioque && key && buffer, PJ_EINVAL); - PJ_CHECK_STACK(); - - /* For consistency with other ioqueue implementation, we would reject - * if descriptor has already been submitted for reading before. - */ - PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_READ) == 0 && - (key->op & PJ_IOQUEUE_OP_RECV) == 0 && - (key->op & PJ_IOQUEUE_OP_RECV_FROM) == 0), - PJ_EBUSY); - - pj_lock_acquire(ioque->lock); - - key->op |= PJ_IOQUEUE_OP_RECV; - key->rd_buf = buffer; - key->rd_buflen = buflen; - key->rd_flags = flags; - PJ_FD_SET(key->fd, &ioque->rfdset); - - pj_lock_release(ioque->lock); - return PJ_EPENDING; -} - -/* - * pj_ioqueue_recvfrom() - * - * Start asynchronous recvfrom() from the socket. - */ -PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - void *buffer, - pj_size_t buflen, - unsigned flags, - pj_sockaddr_t *addr, - int *addrlen) -{ - PJ_ASSERT_RETURN(ioque && key && buffer, PJ_EINVAL); - PJ_CHECK_STACK(); - - /* For consistency with other ioqueue implementation, we would reject - * if descriptor has already been submitted for reading before. - */ - PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_READ) == 0 && - (key->op & PJ_IOQUEUE_OP_RECV) == 0 && - (key->op & PJ_IOQUEUE_OP_RECV_FROM) == 0), - PJ_EBUSY); - - pj_lock_acquire(ioque->lock); - - key->op |= PJ_IOQUEUE_OP_RECV_FROM; - key->rd_buf = buffer; - key->rd_buflen = buflen; - key->rd_flags = flags; - key->rmt_addr = addr; - key->rmt_addrlen = addrlen; - PJ_FD_SET(key->fd, &ioque->rfdset); - - pj_lock_release(ioque->lock); - return PJ_EPENDING; -} - -/* - * pj_ioqueue_write() - * - * Start asynchronous write() to the descriptor. - */ -PJ_DEF(pj_status_t) pj_ioqueue_write( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - const void *data, - pj_size_t datalen) -{ - pj_status_t rc; - pj_ssize_t sent; - - PJ_ASSERT_RETURN(ioque && key && data, PJ_EINVAL); - PJ_CHECK_STACK(); - - /* For consistency with other ioqueue implementation, we would reject - * if descriptor has already been submitted for writing before. - */ - PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_WRITE) == 0 && - (key->op & PJ_IOQUEUE_OP_SEND) == 0 && - (key->op & PJ_IOQUEUE_OP_SEND_TO) == 0), - PJ_EBUSY); - - sent = datalen; - /* sent would be -1 after pj_sock_send() if it returns error. */ - rc = pj_sock_send(key->fd, data, &sent, 0); - if (rc != PJ_SUCCESS && rc != PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) { - return rc; - } - - pj_lock_acquire(ioque->lock); - - key->op |= PJ_IOQUEUE_OP_WRITE; - key->wr_buf = NULL; - key->wr_buflen = datalen; - PJ_FD_SET(key->fd, &ioque->wfdset); - - pj_lock_release(ioque->lock); - - return PJ_EPENDING; -} - -/* - * pj_ioqueue_send() - * - * Start asynchronous send() to the descriptor. - */ -PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - const void *data, - pj_size_t datalen, - unsigned flags) -{ - pj_status_t rc; - pj_ssize_t sent; - - PJ_ASSERT_RETURN(ioque && key && data, PJ_EINVAL); - PJ_CHECK_STACK(); - - /* For consistency with other ioqueue implementation, we would reject - * if descriptor has already been submitted for writing before. - */ - PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_WRITE) == 0 && - (key->op & PJ_IOQUEUE_OP_SEND) == 0 && - (key->op & PJ_IOQUEUE_OP_SEND_TO) == 0), - PJ_EBUSY); - - sent = datalen; - /* sent would be -1 after pj_sock_send() if it returns error. */ - rc = pj_sock_send(key->fd, data, &sent, flags); - if (rc != PJ_SUCCESS && rc != PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) { - return rc; - } - - pj_lock_acquire(ioque->lock); - - key->op |= PJ_IOQUEUE_OP_SEND; - key->wr_buf = NULL; - key->wr_buflen = datalen; - PJ_FD_SET(key->fd, &ioque->wfdset); - - pj_lock_release(ioque->lock); - - return PJ_EPENDING; -} - - -/* - * pj_ioqueue_sendto() - * - * Start asynchronous write() to the descriptor. - */ -PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - const void *data, - pj_size_t datalen, - unsigned flags, - const pj_sockaddr_t *addr, - int addrlen) -{ - pj_status_t rc; - pj_ssize_t sent; - - PJ_ASSERT_RETURN(ioque && key && data, PJ_EINVAL); - PJ_CHECK_STACK(); - - /* For consistency with other ioqueue implementation, we would reject - * if descriptor has already been submitted for writing before. - */ - PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_WRITE) == 0 && - (key->op & PJ_IOQUEUE_OP_SEND) == 0 && - (key->op & PJ_IOQUEUE_OP_SEND_TO) == 0), - PJ_EBUSY); - - sent = datalen; - /* sent would be -1 after pj_sock_sendto() if it returns error. */ - rc = pj_sock_sendto(key->fd, data, &sent, flags, addr, addrlen); - if (rc != PJ_SUCCESS && rc != PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) { - return rc; - } - - pj_lock_acquire(ioque->lock); - - key->op |= PJ_IOQUEUE_OP_SEND_TO; - key->wr_buf = NULL; - key->wr_buflen = datalen; - PJ_FD_SET(key->fd, &ioque->wfdset); - - pj_lock_release(ioque->lock); - return PJ_EPENDING; -} - -#if PJ_HAS_TCP -/* - * Initiate overlapped accept() operation. - */ -PJ_DEF(int) pj_ioqueue_accept( pj_ioqueue_t *ioqueue, - pj_ioqueue_key_t *key, - pj_sock_t *new_sock, - pj_sockaddr_t *local, - pj_sockaddr_t *remote, - int *addrlen) -{ - /* check parameters. All must be specified! */ - pj_assert(ioqueue && key && new_sock); - - /* Server socket must have no other operation! */ - pj_assert(key->op == 0); - - pj_lock_acquire(ioqueue->lock); - - key->op = PJ_IOQUEUE_OP_ACCEPT; - key->accept_fd = new_sock; - key->rmt_addr = remote; - key->rmt_addrlen = addrlen; - key->local_addr = local; - key->local_addrlen = addrlen; /* use same addr. as rmt_addrlen */ - - PJ_FD_SET(key->fd, &ioqueue->rfdset); - - pj_lock_release(ioqueue->lock); - return PJ_EPENDING; -} - -/* - * Initiate overlapped connect() operation (well, it's non-blocking actually, - * since there's no overlapped version of connect()). - */ -PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue, - pj_ioqueue_key_t *key, - const pj_sockaddr_t *addr, - int addrlen ) -{ - pj_status_t rc; - - /* check parameters. All must be specified! */ - PJ_ASSERT_RETURN(ioqueue && key && addr && addrlen, PJ_EINVAL); - - /* Connecting socket must have no other operation! */ - PJ_ASSERT_RETURN(key->op == 0, PJ_EBUSY); - - rc = pj_sock_connect(key->fd, addr, addrlen); - if (rc == PJ_SUCCESS) { - /* Connected! */ - return PJ_SUCCESS; - } else { - if (rc == PJ_STATUS_FROM_OS(OSERR_EINPROGRESS) || - rc == PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) - { - /* Pending! */ - pj_lock_acquire(ioqueue->lock); - key->op = PJ_IOQUEUE_OP_CONNECT; - PJ_FD_SET(key->fd, &ioqueue->wfdset); - PJ_FD_SET(key->fd, &ioqueue->xfdset); - pj_lock_release(ioqueue->lock); - return PJ_EPENDING; - } else { - /* Error! */ - return rc; - } - } -} -#endif /* PJ_HAS_TCP */ - +/* $Header: /pjproject-0.3/pjlib/src/pj/ioqueue_select.c 15 10/29/05 10:27p Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/ioqueue_select.c $ + * + * 15 10/29/05 10:27p Bennylp + * Fixed misc warnings. + * + * 14 10/29/05 11:31a Bennylp + * Changed accept and lock. + * + * 13 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 12 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 11 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ + +/* + * sock_select.c + * + * This is the implementation of IOQueue using pj_sock_select(). + * It runs anywhere where pj_sock_select() is available (currently + * Win32, Linux, Linux kernel, etc.). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * ISSUES with ioqueue_select() + * + * EAGAIN/EWOULDBLOCK error in recv(): + * - when multiple threads are working with the ioqueue, application + * may receive EAGAIN or EWOULDBLOCK in the receive callback. + * This error happens because more than one thread is watching for + * the same descriptor set, so when all of them call recv() or recvfrom() + * simultaneously, only one will succeed and the rest will get the error. + * + */ +#define THIS_FILE "ioq_select" + +#define PJ_IOQUEUE_IS_READ_OP(op) ((op & PJ_IOQUEUE_OP_READ) || \ + (op & PJ_IOQUEUE_OP_RECV) || \ + (op & PJ_IOQUEUE_OP_RECV_FROM)) +#define PJ_IOQUEUE_IS_WRITE_OP(op) ((op & PJ_IOQUEUE_OP_WRITE) || \ + (op & PJ_IOQUEUE_OP_SEND) || \ + (op & PJ_IOQUEUE_OP_SEND_TO)) + + +#if PJ_HAS_TCP +# define PJ_IOQUEUE_IS_ACCEPT_OP(op) (op & PJ_IOQUEUE_OP_ACCEPT) +# define PJ_IOQUEUE_IS_CONNECT_OP(op) (op & PJ_IOQUEUE_OP_CONNECT) +#else +# define PJ_IOQUEUE_IS_ACCEPT_OP(op) 0 +# define PJ_IOQUEUE_IS_CONNECT_OP(op) 0 +#endif + +/* + * During debugging build, VALIDATE_FD_SET is set. + * This will check the validity of the fd_sets. + */ +#if defined(PJ_DEBUG) && PJ_DEBUG != 0 +# define VALIDATE_FD_SET 1 +#else +# define VALIDATE_FD_SET 0 +#endif + +/* + * This describes each key. + */ +struct pj_ioqueue_key_t +{ + PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t) + pj_sock_t fd; + pj_ioqueue_operation_e op; + void *user_data; + pj_ioqueue_callback cb; + + void *rd_buf; + unsigned rd_flags; + pj_size_t rd_buflen; + void *wr_buf; + pj_size_t wr_buflen; + + pj_sockaddr_t *rmt_addr; + int *rmt_addrlen; + + pj_sockaddr_t *local_addr; + int *local_addrlen; + + pj_sock_t *accept_fd; +}; + +/* + * This describes the I/O queue itself. + */ +struct pj_ioqueue_t +{ + pj_lock_t *lock; + pj_bool_t auto_delete_lock; + unsigned max, count; + pj_ioqueue_key_t hlist; + pj_fd_set_t rfdset; + pj_fd_set_t wfdset; +#if PJ_HAS_TCP + pj_fd_set_t xfdset; +#endif +}; + +/* + * pj_ioqueue_create() + * + * Create select ioqueue. + */ +PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, + pj_size_t max_fd, + int max_threads, + pj_ioqueue_t **p_ioqueue) +{ + pj_ioqueue_t *ioque; + pj_status_t rc; + + PJ_UNUSED_ARG(max_threads); + + if (max_fd > PJ_IOQUEUE_MAX_HANDLES) { + pj_assert(!"max_fd too large"); + return PJ_EINVAL; + } + + ioque = pj_pool_alloc(pool, sizeof(pj_ioqueue_t)); + ioque->max = max_fd; + ioque->count = 0; + PJ_FD_ZERO(&ioque->rfdset); + PJ_FD_ZERO(&ioque->wfdset); +#if PJ_HAS_TCP + PJ_FD_ZERO(&ioque->xfdset); +#endif + pj_list_init(&ioque->hlist); + + rc = pj_lock_create_recursive_mutex(pool, "ioq%p", &ioque->lock); + if (rc != PJ_SUCCESS) + return rc; + + ioque->auto_delete_lock = PJ_TRUE; + + PJ_LOG(4, ("pjlib", "select() I/O Queue created (%p)", ioque)); + + *p_ioqueue = ioque; + return PJ_SUCCESS; +} + +/* + * pj_ioqueue_destroy() + * + * Destroy ioqueue. + */ +PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque) +{ + pj_status_t rc = PJ_SUCCESS; + + PJ_ASSERT_RETURN(ioque, PJ_EINVAL); + + if (ioque->auto_delete_lock) + rc = pj_lock_destroy(ioque->lock); + + return rc; +} + + +/* + * pj_ioqueue_set_lock() + */ +PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, + pj_lock_t *lock, + pj_bool_t auto_delete ) +{ + PJ_ASSERT_RETURN(ioque && lock, PJ_EINVAL); + + if (ioque->auto_delete_lock) { + pj_lock_destroy(ioque->lock); + } + + ioque->lock = lock; + ioque->auto_delete_lock = auto_delete; + + return PJ_SUCCESS; +} + + +/* + * pj_ioqueue_register_sock() + * + * Register a handle to ioqueue. + */ +PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool, + pj_ioqueue_t *ioque, + pj_sock_t sock, + void *user_data, + const pj_ioqueue_callback *cb, + pj_ioqueue_key_t **p_key) +{ + pj_ioqueue_key_t *key = NULL; + pj_uint32_t value; + pj_status_t rc = PJ_SUCCESS; + + PJ_ASSERT_RETURN(pool && ioque && sock != PJ_INVALID_SOCKET && + cb && p_key, PJ_EINVAL); + + pj_lock_acquire(ioque->lock); + + if (ioque->count >= ioque->max) { + rc = PJ_ETOOMANY; + goto on_return; + } + + /* Set socket to nonblocking. */ + value = 1; +#ifdef PJ_WIN32 + if (ioctlsocket(sock, FIONBIO, (unsigned long*)&value)) { +#else + if (ioctl(sock, FIONBIO, &value)) { +#endif + rc = pj_get_netos_error(); + goto on_return; + } + + /* Create key. */ + key = (pj_ioqueue_key_t*)pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t)); + key->fd = sock; + key->user_data = user_data; + + /* Save callback. */ + pj_memcpy(&key->cb, cb, sizeof(pj_ioqueue_callback)); + + /* Register */ + pj_list_insert_before(&ioque->hlist, key); + ++ioque->count; + +on_return: + *p_key = key; + pj_lock_release(ioque->lock); + + return rc; +} + +/* + * pj_ioqueue_unregister() + * + * Unregister handle from ioqueue. + */ +PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key) +{ + PJ_ASSERT_RETURN(ioque && key, PJ_EINVAL); + + pj_lock_acquire(ioque->lock); + + pj_assert(ioque->count > 0); + --ioque->count; + pj_list_erase(key); + PJ_FD_CLR(key->fd, &ioque->rfdset); + PJ_FD_CLR(key->fd, &ioque->wfdset); +#if PJ_HAS_TCP + PJ_FD_CLR(key->fd, &ioque->xfdset); +#endif + + pj_lock_release(ioque->lock); + return PJ_SUCCESS; +} + +/* + * pj_ioqueue_get_user_data() + * + * Obtain value associated with a key. + */ +PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key ) +{ + PJ_ASSERT_RETURN(key != NULL, NULL); + return key->user_data; +} + + +/* This supposed to check whether the fd_set values are consistent + * with the operation currently set in each key. + */ +#if VALIDATE_FD_SET +static void validate_sets(const pj_ioqueue_t *ioque, + const pj_fd_set_t *rfdset, + const pj_fd_set_t *wfdset, + const pj_fd_set_t *xfdset) +{ + pj_ioqueue_key_t *key; + + key = ioque->hlist.next; + while (key != &ioque->hlist) { + if ((key->op & PJ_IOQUEUE_OP_READ) + || (key->op & PJ_IOQUEUE_OP_RECV) + || (key->op & PJ_IOQUEUE_OP_RECV_FROM) +#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 + || (key->op & PJ_IOQUEUE_OP_ACCEPT) +#endif + ) + { + pj_assert(PJ_FD_ISSET(key->fd, rfdset)); + } + else { + pj_assert(PJ_FD_ISSET(key->fd, rfdset) == 0); + } + if ((key->op & PJ_IOQUEUE_OP_WRITE) + || (key->op & PJ_IOQUEUE_OP_SEND) + || (key->op & PJ_IOQUEUE_OP_SEND_TO) +#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 + || (key->op & PJ_IOQUEUE_OP_CONNECT) +#endif + ) + { + pj_assert(PJ_FD_ISSET(key->fd, wfdset)); + } + else { + pj_assert(PJ_FD_ISSET(key->fd, wfdset) == 0); + } +#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 + if (key->op & PJ_IOQUEUE_OP_CONNECT) + { + pj_assert(PJ_FD_ISSET(key->fd, xfdset)); + } + else { + pj_assert(PJ_FD_ISSET(key->fd, xfdset) == 0); + } +#endif /* PJ_HAS_TCP */ + + key = key->next; + } +} +#endif /* VALIDATE_FD_SET */ + + +/* + * pj_ioqueue_poll() + * + * Few things worth written: + * + * - we used to do only one callback called per poll, but it didn't go + * very well. The reason is because on some situation, the write + * callback gets called all the time, thus doesn't give the read + * callback to get called. This happens, for example, when user + * submit write operation inside the write callback. + * As the result, we changed the behaviour so that now multiple + * callbacks are called in a single poll. It should be fast too, + * just that we need to be carefull with the ioqueue data structs. + * + * - to guarantee preemptiveness etc, the poll function must strictly + * work on fd_set copy of the ioqueue (not the original one). + */ +PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout) +{ + pj_fd_set_t rfdset, wfdset, xfdset; + int count; + pj_ioqueue_key_t *h; + + /* Lock ioqueue before making fd_set copies */ + pj_lock_acquire(ioque->lock); + + if (PJ_FD_COUNT(&ioque->rfdset)==0 && + PJ_FD_COUNT(&ioque->wfdset)==0 && + PJ_FD_COUNT(&ioque->xfdset)==0) + { + pj_lock_release(ioque->lock); + if (timeout) + pj_thread_sleep(PJ_TIME_VAL_MSEC(*timeout)); + return 0; + } + + /* Copy ioqueue's pj_fd_set_t to local variables. */ + pj_memcpy(&rfdset, &ioque->rfdset, sizeof(pj_fd_set_t)); + pj_memcpy(&wfdset, &ioque->wfdset, sizeof(pj_fd_set_t)); +#if PJ_HAS_TCP + pj_memcpy(&xfdset, &ioque->xfdset, sizeof(pj_fd_set_t)); +#else + PJ_FD_ZERO(&xfdset); +#endif + +#if VALIDATE_FD_SET + validate_sets(ioque, &rfdset, &wfdset, &xfdset); +#endif + + /* Unlock ioqueue before select(). */ + pj_lock_release(ioque->lock); + + count = pj_sock_select(FD_SETSIZE, &rfdset, &wfdset, &xfdset, timeout); + + if (count <= 0) + return count; + + /* Lock ioqueue again before scanning for signalled sockets. */ + pj_lock_acquire(ioque->lock); + +#if PJ_HAS_TCP + /* Scan for exception socket */ + h = ioque->hlist.next; +do_except_scan: + for ( ; h!=&ioque->hlist; h = h->next) { + if ((h->op & PJ_IOQUEUE_OP_CONNECT) && PJ_FD_ISSET(h->fd, &xfdset)) + break; + } + if (h != &ioque->hlist) { + /* 'connect()' should be the only operation. */ + pj_assert((h->op == PJ_IOQUEUE_OP_CONNECT)); + + /* Clear operation. */ + h->op &= ~(PJ_IOQUEUE_OP_CONNECT); + PJ_FD_CLR(h->fd, &ioque->wfdset); + PJ_FD_CLR(h->fd, &ioque->xfdset); + PJ_FD_CLR(h->fd, &wfdset); + PJ_FD_CLR(h->fd, &xfdset); + + /* Call callback. */ + if (h->cb.on_connect_complete) + (*h->cb.on_connect_complete)(h, -1); + + /* Re-scan exception list. */ + goto do_except_scan; + } +#endif /* PJ_HAS_TCP */ + + /* Scan for readable socket. */ + h = ioque->hlist.next; +do_readable_scan: + for ( ; h!=&ioque->hlist; h = h->next) { + if ((PJ_IOQUEUE_IS_READ_OP(h->op) || PJ_IOQUEUE_IS_ACCEPT_OP(h->op)) && + PJ_FD_ISSET(h->fd, &rfdset)) + { + break; + } + } + if (h != &ioque->hlist) { + pj_status_t rc; + + pj_assert(PJ_IOQUEUE_IS_READ_OP(h->op) || + PJ_IOQUEUE_IS_ACCEPT_OP(h->op)); + +# if PJ_HAS_TCP + if ((h->op & PJ_IOQUEUE_OP_ACCEPT)) { + /* accept() must be the only operation specified on server socket */ + pj_assert(h->op == PJ_IOQUEUE_OP_ACCEPT); + + rc=pj_sock_accept(h->fd, h->accept_fd, h->rmt_addr, h->rmt_addrlen); + if (rc==0 && h->local_addr) { + rc = pj_sock_getsockname(*h->accept_fd, h->local_addr, + h->local_addrlen); + } + + h->op &= ~(PJ_IOQUEUE_OP_ACCEPT); + PJ_FD_CLR(h->fd, &ioque->rfdset); + + /* Call callback. */ + if (h->cb.on_accept_complete) + (*h->cb.on_accept_complete)(h, *h->accept_fd, rc); + + /* Re-scan readable sockets. */ + goto do_readable_scan; + } + else { +# endif + pj_ssize_t bytes_read = h->rd_buflen; + + if ((h->op & PJ_IOQUEUE_OP_RECV_FROM)) { + rc = pj_sock_recvfrom(h->fd, h->rd_buf, &bytes_read, 0, + h->rmt_addr, h->rmt_addrlen); + } else if ((h->op & PJ_IOQUEUE_OP_RECV)) { + rc = pj_sock_recv(h->fd, h->rd_buf, &bytes_read, 0); + } else { + /* + * User has specified pj_ioqueue_read(). + * On Win32, we should do ReadFile(). But because we got + * here because of select() anyway, user must have put a + * socket descriptor on h->fd, which in this case we can + * just call pj_sock_recv() instead of ReadFile(). + * On Unix, user may put a file in h->fd, so we'll have + * to call read() here. + * This may not compile on systems which doesn't have + * read(). That's why we only specify PJ_LINUX here so + * that error is easier to catch. + */ +# if defined(PJ_WIN32) && PJ_WIN32 != 0 + rc = pj_sock_recv(h->fd, h->rd_buf, &bytes_read, 0); +# elif (defined(PJ_LINUX) && PJ_LINUX != 0) || \ + (defined(PJ_SUNOS) && PJ_SUNOS != 0) + bytes_read = read(h->fd, h->rd_buf, bytes_read); + rc = (bytes_read >= 0) ? PJ_SUCCESS : pj_get_os_error(); +# elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0 + bytes_read = sys_read(h->fd, h->rd_buf, bytes_read); + rc = (bytes_read >= 0) ? PJ_SUCCESS : -bytes_read; +# else +# error "Implement read() for this platform!" +# endif + } + + if (rc != PJ_SUCCESS) { +# if defined(PJ_WIN32) && PJ_WIN32 != 0 + /* On Win32, for UDP, WSAECONNRESET on the receive side + * indicates that previous sending has triggered ICMP Port + * Unreachable message. + * But we wouldn't know at this point which one of previous + * key that has triggered the error, since UDP socket can + * be shared! + * So we'll just ignore it! + */ + + if (rc == PJ_STATUS_FROM_OS(WSAECONNRESET)) { + PJ_LOG(4,(THIS_FILE, + "Ignored ICMP port unreach. on key=%p", h)); + } +# endif + + /* In any case we would report this to caller. */ + bytes_read = -rc; + } + + h->op &= ~(PJ_IOQUEUE_OP_READ | PJ_IOQUEUE_OP_RECV | + PJ_IOQUEUE_OP_RECV_FROM); + PJ_FD_CLR(h->fd, &ioque->rfdset); + PJ_FD_CLR(h->fd, &rfdset); + + /* Call callback. */ + if (h->cb.on_read_complete) + (*h->cb.on_read_complete)(h, bytes_read); + + /* Re-scan readable sockets. */ + goto do_readable_scan; + + } + } + + /* Scan for writable socket */ + h = ioque->hlist.next; +do_writable_scan: + for ( ; h!=&ioque->hlist; h = h->next) { + if ((PJ_IOQUEUE_IS_WRITE_OP(h->op) || PJ_IOQUEUE_IS_CONNECT_OP(h->op)) + && PJ_FD_ISSET(h->fd, &wfdset)) + { + break; + } + } + if (h != &ioque->hlist) { + pj_assert(PJ_IOQUEUE_IS_WRITE_OP(h->op) || + PJ_IOQUEUE_IS_CONNECT_OP(h->op)); + +#if defined(PJ_HAS_TCP) && PJ_HAS_TCP!=0 + if ((h->op & PJ_IOQUEUE_OP_CONNECT)) { + /* Completion of connect() operation */ + pj_ssize_t bytes_transfered; + +#if (defined(PJ_LINUX) && PJ_LINUX!=0) || \ + (defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL!=0) + /* from connect(2): + * On Linux, use getsockopt to read the SO_ERROR option at + * level SOL_SOCKET to determine whether connect() completed + * successfully (if SO_ERROR is zero). + */ + int value; + socklen_t vallen = sizeof(value); + int gs_rc = getsockopt(h->fd, SOL_SOCKET, SO_ERROR, + &value, &vallen); + if (gs_rc != 0) { + /* Argh!! What to do now??? + * Just indicate that the socket is connected. The + * application will get error as soon as it tries to use + * the socket to send/receive. + */ + bytes_transfered = 0; + } else { + bytes_transfered = value; + } +#elif defined(PJ_WIN32) && PJ_WIN32!=0 + bytes_transfered = 0; /* success */ +#else + /* Excellent information in D.J. Bernstein page: + * http://cr.yp.to/docs/connect.html + * + * Seems like the most portable way of detecting connect() + * failure is to call getpeername(). If socket is connected, + * getpeername() will return 0. If the socket is not connected, + * it will return ENOTCONN, and read(fd, &ch, 1) will produce + * the right errno through error slippage. This is a combination + * of suggestions from Douglas C. Schmidt and Ken Keys. + */ + int gp_rc; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); + + gp_rc = getpeername(h->fd, (struct sockaddr*)&addr, &addrlen); + bytes_transfered = gp_rc; +#endif + + /* Clear operation. */ + h->op &= (~PJ_IOQUEUE_OP_CONNECT); + PJ_FD_CLR(h->fd, &ioque->wfdset); + PJ_FD_CLR(h->fd, &ioque->xfdset); + + /* Call callback. */ + if (h->cb.on_connect_complete) + (*h->cb.on_connect_complete)(h, bytes_transfered); + + /* Re-scan writable sockets. */ + goto do_writable_scan; + + } else +#endif /* PJ_HAS_TCP */ + { + /* Completion of write(), send(), or sendto() operation. */ + + /* Clear operation. */ + h->op &= ~(PJ_IOQUEUE_OP_WRITE | PJ_IOQUEUE_OP_SEND | + PJ_IOQUEUE_OP_SEND_TO); + PJ_FD_CLR(h->fd, &ioque->wfdset); + PJ_FD_CLR(h->fd, &wfdset); + + /* Call callback. */ + /* All data must have been sent? */ + if (h->cb.on_write_complete) + (*h->cb.on_write_complete)(h, h->wr_buflen); + + /* Re-scan writable sockets. */ + goto do_writable_scan; + } + } + + /* Shouldn't happen. */ + /* For strange reason on WinXP select() can return 1 while there is no + * pj_fd_set_t signaled. */ + /* pj_assert(0); */ + + //count = 0; + + pj_lock_release(ioque->lock); + return count; +} + +/* + * pj_ioqueue_read() + * + * Start asynchronous read from the descriptor. + */ +PJ_DEF(pj_status_t) pj_ioqueue_read( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + void *buffer, + pj_size_t buflen) +{ + PJ_ASSERT_RETURN(ioque && key && buffer, PJ_EINVAL); + PJ_CHECK_STACK(); + + /* For consistency with other ioqueue implementation, we would reject + * if descriptor has already been submitted for reading before. + */ + PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_READ) == 0 && + (key->op & PJ_IOQUEUE_OP_RECV) == 0 && + (key->op & PJ_IOQUEUE_OP_RECV_FROM) == 0), + PJ_EBUSY); + + pj_lock_acquire(ioque->lock); + + key->op |= PJ_IOQUEUE_OP_READ; + key->rd_flags = 0; + key->rd_buf = buffer; + key->rd_buflen = buflen; + PJ_FD_SET(key->fd, &ioque->rfdset); + + pj_lock_release(ioque->lock); + return PJ_EPENDING; +} + + +/* + * pj_ioqueue_recv() + * + * Start asynchronous recv() from the socket. + */ +PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + void *buffer, + pj_size_t buflen, + unsigned flags ) +{ + PJ_ASSERT_RETURN(ioque && key && buffer, PJ_EINVAL); + PJ_CHECK_STACK(); + + /* For consistency with other ioqueue implementation, we would reject + * if descriptor has already been submitted for reading before. + */ + PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_READ) == 0 && + (key->op & PJ_IOQUEUE_OP_RECV) == 0 && + (key->op & PJ_IOQUEUE_OP_RECV_FROM) == 0), + PJ_EBUSY); + + pj_lock_acquire(ioque->lock); + + key->op |= PJ_IOQUEUE_OP_RECV; + key->rd_buf = buffer; + key->rd_buflen = buflen; + key->rd_flags = flags; + PJ_FD_SET(key->fd, &ioque->rfdset); + + pj_lock_release(ioque->lock); + return PJ_EPENDING; +} + +/* + * pj_ioqueue_recvfrom() + * + * Start asynchronous recvfrom() from the socket. + */ +PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + void *buffer, + pj_size_t buflen, + unsigned flags, + pj_sockaddr_t *addr, + int *addrlen) +{ + PJ_ASSERT_RETURN(ioque && key && buffer, PJ_EINVAL); + PJ_CHECK_STACK(); + + /* For consistency with other ioqueue implementation, we would reject + * if descriptor has already been submitted for reading before. + */ + PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_READ) == 0 && + (key->op & PJ_IOQUEUE_OP_RECV) == 0 && + (key->op & PJ_IOQUEUE_OP_RECV_FROM) == 0), + PJ_EBUSY); + + pj_lock_acquire(ioque->lock); + + key->op |= PJ_IOQUEUE_OP_RECV_FROM; + key->rd_buf = buffer; + key->rd_buflen = buflen; + key->rd_flags = flags; + key->rmt_addr = addr; + key->rmt_addrlen = addrlen; + PJ_FD_SET(key->fd, &ioque->rfdset); + + pj_lock_release(ioque->lock); + return PJ_EPENDING; +} + +/* + * pj_ioqueue_write() + * + * Start asynchronous write() to the descriptor. + */ +PJ_DEF(pj_status_t) pj_ioqueue_write( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + const void *data, + pj_size_t datalen) +{ + pj_status_t rc; + pj_ssize_t sent; + + PJ_ASSERT_RETURN(ioque && key && data, PJ_EINVAL); + PJ_CHECK_STACK(); + + /* For consistency with other ioqueue implementation, we would reject + * if descriptor has already been submitted for writing before. + */ + PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_WRITE) == 0 && + (key->op & PJ_IOQUEUE_OP_SEND) == 0 && + (key->op & PJ_IOQUEUE_OP_SEND_TO) == 0), + PJ_EBUSY); + + sent = datalen; + /* sent would be -1 after pj_sock_send() if it returns error. */ + rc = pj_sock_send(key->fd, data, &sent, 0); + if (rc != PJ_SUCCESS && rc != PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) { + return rc; + } + + pj_lock_acquire(ioque->lock); + + key->op |= PJ_IOQUEUE_OP_WRITE; + key->wr_buf = NULL; + key->wr_buflen = datalen; + PJ_FD_SET(key->fd, &ioque->wfdset); + + pj_lock_release(ioque->lock); + + return PJ_EPENDING; +} + +/* + * pj_ioqueue_send() + * + * Start asynchronous send() to the descriptor. + */ +PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + const void *data, + pj_size_t datalen, + unsigned flags) +{ + pj_status_t rc; + pj_ssize_t sent; + + PJ_ASSERT_RETURN(ioque && key && data, PJ_EINVAL); + PJ_CHECK_STACK(); + + /* For consistency with other ioqueue implementation, we would reject + * if descriptor has already been submitted for writing before. + */ + PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_WRITE) == 0 && + (key->op & PJ_IOQUEUE_OP_SEND) == 0 && + (key->op & PJ_IOQUEUE_OP_SEND_TO) == 0), + PJ_EBUSY); + + sent = datalen; + /* sent would be -1 after pj_sock_send() if it returns error. */ + rc = pj_sock_send(key->fd, data, &sent, flags); + if (rc != PJ_SUCCESS && rc != PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) { + return rc; + } + + pj_lock_acquire(ioque->lock); + + key->op |= PJ_IOQUEUE_OP_SEND; + key->wr_buf = NULL; + key->wr_buflen = datalen; + PJ_FD_SET(key->fd, &ioque->wfdset); + + pj_lock_release(ioque->lock); + + return PJ_EPENDING; +} + + +/* + * pj_ioqueue_sendto() + * + * Start asynchronous write() to the descriptor. + */ +PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + const void *data, + pj_size_t datalen, + unsigned flags, + const pj_sockaddr_t *addr, + int addrlen) +{ + pj_status_t rc; + pj_ssize_t sent; + + PJ_ASSERT_RETURN(ioque && key && data, PJ_EINVAL); + PJ_CHECK_STACK(); + + /* For consistency with other ioqueue implementation, we would reject + * if descriptor has already been submitted for writing before. + */ + PJ_ASSERT_RETURN(((key->op & PJ_IOQUEUE_OP_WRITE) == 0 && + (key->op & PJ_IOQUEUE_OP_SEND) == 0 && + (key->op & PJ_IOQUEUE_OP_SEND_TO) == 0), + PJ_EBUSY); + + sent = datalen; + /* sent would be -1 after pj_sock_sendto() if it returns error. */ + rc = pj_sock_sendto(key->fd, data, &sent, flags, addr, addrlen); + if (rc != PJ_SUCCESS && rc != PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) { + return rc; + } + + pj_lock_acquire(ioque->lock); + + key->op |= PJ_IOQUEUE_OP_SEND_TO; + key->wr_buf = NULL; + key->wr_buflen = datalen; + PJ_FD_SET(key->fd, &ioque->wfdset); + + pj_lock_release(ioque->lock); + return PJ_EPENDING; +} + +#if PJ_HAS_TCP +/* + * Initiate overlapped accept() operation. + */ +PJ_DEF(int) pj_ioqueue_accept( pj_ioqueue_t *ioqueue, + pj_ioqueue_key_t *key, + pj_sock_t *new_sock, + pj_sockaddr_t *local, + pj_sockaddr_t *remote, + int *addrlen) +{ + /* check parameters. All must be specified! */ + pj_assert(ioqueue && key && new_sock); + + /* Server socket must have no other operation! */ + pj_assert(key->op == 0); + + pj_lock_acquire(ioqueue->lock); + + key->op = PJ_IOQUEUE_OP_ACCEPT; + key->accept_fd = new_sock; + key->rmt_addr = remote; + key->rmt_addrlen = addrlen; + key->local_addr = local; + key->local_addrlen = addrlen; /* use same addr. as rmt_addrlen */ + + PJ_FD_SET(key->fd, &ioqueue->rfdset); + + pj_lock_release(ioqueue->lock); + return PJ_EPENDING; +} + +/* + * Initiate overlapped connect() operation (well, it's non-blocking actually, + * since there's no overlapped version of connect()). + */ +PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue, + pj_ioqueue_key_t *key, + const pj_sockaddr_t *addr, + int addrlen ) +{ + pj_status_t rc; + + /* check parameters. All must be specified! */ + PJ_ASSERT_RETURN(ioqueue && key && addr && addrlen, PJ_EINVAL); + + /* Connecting socket must have no other operation! */ + PJ_ASSERT_RETURN(key->op == 0, PJ_EBUSY); + + rc = pj_sock_connect(key->fd, addr, addrlen); + if (rc == PJ_SUCCESS) { + /* Connected! */ + return PJ_SUCCESS; + } else { + if (rc == PJ_STATUS_FROM_OS(OSERR_EINPROGRESS) || + rc == PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) + { + /* Pending! */ + pj_lock_acquire(ioqueue->lock); + key->op = PJ_IOQUEUE_OP_CONNECT; + PJ_FD_SET(key->fd, &ioqueue->wfdset); + PJ_FD_SET(key->fd, &ioqueue->xfdset); + pj_lock_release(ioqueue->lock); + return PJ_EPENDING; + } else { + /* Error! */ + return rc; + } + } +} +#endif /* PJ_HAS_TCP */ + diff --git a/pjlib/src/pj/ioqueue_winnt.c b/pjlib/src/pj/ioqueue_winnt.c index 93116c9d..2a8fd7e8 100644 --- a/pjlib/src/pj/ioqueue_winnt.c +++ b/pjlib/src/pj/ioqueue_winnt.c @@ -1,852 +1,852 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/ioqueue_winnt.c 11 10/29/05 11:31a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/ioqueue_winnt.c $ - * - * 11 10/29/05 11:31a Bennylp - * Changed accept and lock. - * - * 10 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 9 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0 -# include -#elif defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0 -# include -#endif - -#if defined(PJ_HAS_MSWSOCK_H) && PJ_HAS_MSWSOCK_H != 0 -# include -#endif - - -#define ACCEPT_ADDR_LEN (sizeof(pj_sockaddr_in)+20) - -/* - * OVERLAP structure for send and receive. - */ -typedef struct ioqueue_overlapped -{ - WSAOVERLAPPED overlapped; - pj_ioqueue_operation_e operation; - WSABUF wsabuf; -} ioqueue_overlapped; - -#if PJ_HAS_TCP -/* - * OVERLAP structure for accept. - */ -typedef struct ioqueue_accept_rec -{ - WSAOVERLAPPED overlapped; - pj_ioqueue_operation_e operation; - pj_sock_t newsock; - pj_sock_t *newsock_ptr; - int *addrlen; - void *remote; - void *local; - char accept_buf[2 * ACCEPT_ADDR_LEN]; -} ioqueue_accept_rec; -#endif - -/* - * Structure for individual socket. - */ -struct pj_ioqueue_key_t -{ - HANDLE hnd; - void *user_data; - ioqueue_overlapped recv_overlapped; - ioqueue_overlapped send_overlapped; -#if PJ_HAS_TCP - int connecting; - ioqueue_accept_rec accept_overlapped; -#endif - pj_ioqueue_callback cb; -}; - -/* - * IO Queue structure. - */ -struct pj_ioqueue_t -{ - HANDLE iocp; - pj_lock_t *lock; - pj_bool_t auto_delete_lock; - unsigned event_count; - HANDLE event_pool[MAXIMUM_WAIT_OBJECTS+1]; -#if PJ_HAS_TCP - unsigned connecting_count; - HANDLE connecting_handles[MAXIMUM_WAIT_OBJECTS+1]; - pj_ioqueue_key_t *connecting_keys[MAXIMUM_WAIT_OBJECTS+1]; -#endif -}; - - -#if PJ_HAS_TCP -/* - * Process the socket when the overlapped accept() completed. - */ -static void ioqueue_on_accept_complete(ioqueue_accept_rec *accept_overlapped) -{ - struct sockaddr *local; - struct sockaddr *remote; - int locallen, remotelen; - - PJ_CHECK_STACK(); - - /* Operation complete immediately. */ - GetAcceptExSockaddrs( accept_overlapped->accept_buf, - 0, - ACCEPT_ADDR_LEN, - ACCEPT_ADDR_LEN, - &local, - &locallen, - &remote, - &remotelen); - pj_memcpy(accept_overlapped->local, local, locallen); - pj_memcpy(accept_overlapped->remote, remote, locallen); - *accept_overlapped->addrlen = locallen; - if (accept_overlapped->newsock_ptr) - *accept_overlapped->newsock_ptr = accept_overlapped->newsock; - accept_overlapped->operation = 0; - accept_overlapped->newsock = PJ_INVALID_SOCKET; -} - -static void erase_connecting_socket( pj_ioqueue_t *ioqueue, unsigned pos) -{ - pj_ioqueue_key_t *key = ioqueue->connecting_keys[pos]; - HANDLE hEvent = ioqueue->connecting_handles[pos]; - unsigned long optval; - - /* Remove key from array of connecting handles. */ - pj_array_erase(ioqueue->connecting_keys, sizeof(key), - ioqueue->connecting_count, pos); - pj_array_erase(ioqueue->connecting_handles, sizeof(HANDLE), - ioqueue->connecting_count, pos); - --ioqueue->connecting_count; - - /* Disassociate the socket from the event. */ - WSAEventSelect((pj_sock_t)key->hnd, hEvent, 0); - - /* Put event object to pool. */ - if (ioqueue->event_count < MAXIMUM_WAIT_OBJECTS) { - ioqueue->event_pool[ioqueue->event_count++] = hEvent; - } else { - /* Shouldn't happen. There should be no more pending connections - * than max. - */ - pj_assert(0); - CloseHandle(hEvent); - } - - /* Set socket to blocking again. */ - optval = 0; - if (ioctlsocket((pj_sock_t)key->hnd, FIONBIO, &optval) != 0) { - DWORD dwStatus; - dwStatus = WSAGetLastError(); - } -} - -/* - * Poll for the completion of non-blocking connect(). - * If there's a completion, the function return the key of the completed - * socket, and 'result' argument contains the connect() result. If connect() - * succeeded, 'result' will have value zero, otherwise will have the error - * code. - */ -static pj_ioqueue_key_t *check_connecting( pj_ioqueue_t *ioqueue, - pj_ssize_t *connect_err ) -{ - pj_ioqueue_key_t *key = NULL; - - if (ioqueue->connecting_count) { - DWORD result; - - pj_lock_acquire(ioqueue->lock); - result = WaitForMultipleObjects(ioqueue->connecting_count, - ioqueue->connecting_handles, - FALSE, 0); - if (result >= WAIT_OBJECT_0 && - result < WAIT_OBJECT_0+ioqueue->connecting_count) - { - WSANETWORKEVENTS net_events; - - /* Got completed connect(). */ - unsigned pos = result - WAIT_OBJECT_0; - key = ioqueue->connecting_keys[pos]; - - /* See whether connect has succeeded. */ - WSAEnumNetworkEvents((pj_sock_t)key->hnd, - ioqueue->connecting_handles[pos], - &net_events); - *connect_err = net_events.iErrorCode[FD_CONNECT_BIT]; - - /* Erase socket from pending connect. */ - erase_connecting_socket(ioqueue, pos); - } - pj_lock_release(ioqueue->lock); - } - return key; -} -#endif - - -PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, - pj_size_t max_fd, - int max_threads, - pj_ioqueue_t **ioqueue) -{ - pj_ioqueue_t *ioq; - pj_status_t rc; - - PJ_UNUSED_ARG(max_fd); - PJ_ASSERT_RETURN(pool && ioqueue, PJ_EINVAL); - - ioq = pj_pool_zalloc(pool, sizeof(*ioq)); - ioq->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, max_threads); - if (ioq->iocp == NULL) - return PJ_RETURN_OS_ERROR(GetLastError()); - - rc = pj_lock_create_simple_mutex(pool, NULL, &ioq->lock); - if (rc != PJ_SUCCESS) { - CloseHandle(ioq->iocp); - return rc; - } - - ioq->auto_delete_lock = PJ_TRUE; - - *ioqueue = ioq; - - PJ_LOG(4, ("pjlib", "WinNT IOCP I/O Queue created (%p)", ioq)); - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioque ) -{ - unsigned i; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(ioque, PJ_EINVAL); - - /* Destroy events in the pool */ - for (i=0; ievent_count; ++i) { - CloseHandle(ioque->event_pool[i]); - } - ioque->event_count = 0; - - if (ioque->auto_delete_lock) - pj_lock_destroy(ioque->lock); - - if (CloseHandle(ioque->iocp) == TRUE) - return PJ_SUCCESS; - else - return PJ_RETURN_OS_ERROR(GetLastError()); -} - -PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, - pj_lock_t *lock, - pj_bool_t auto_delete ) -{ - PJ_ASSERT_RETURN(ioque && lock, PJ_EINVAL); - - if (ioque->auto_delete_lock) { - pj_lock_destroy(ioque->lock); - } - - ioque->lock = lock; - ioque->auto_delete_lock = auto_delete; - - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool, - pj_ioqueue_t *ioque, - pj_sock_t hnd, - void *user_data, - const pj_ioqueue_callback *cb, - pj_ioqueue_key_t **key ) -{ - HANDLE hioq; - pj_ioqueue_key_t *rec; - - PJ_ASSERT_RETURN(pool && ioque && cb && key, PJ_EINVAL); - - rec = pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t)); - rec->hnd = (HANDLE)hnd; - rec->user_data = user_data; - pj_memcpy(&rec->cb, cb, sizeof(pj_ioqueue_callback)); -#if PJ_HAS_TCP - rec->accept_overlapped.newsock = PJ_INVALID_SOCKET; -#endif - hioq = CreateIoCompletionPort((HANDLE)hnd, ioque->iocp, (DWORD)rec, 0); - if (!hioq) { - return PJ_RETURN_OS_ERROR(GetLastError()); - } - - *key = rec; - return PJ_SUCCESS; -} - - - -PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key ) -{ - PJ_ASSERT_RETURN(ioque && key, PJ_EINVAL); - -#if PJ_HAS_TCP - if (key->connecting) { - unsigned pos; - - /* Erase from connecting_handles */ - pj_lock_acquire(ioque->lock); - for (pos=0; pos < ioque->connecting_count; ++pos) { - if (ioque->connecting_keys[pos] == key) { - erase_connecting_socket(ioque, pos); - if (key->accept_overlapped.newsock_ptr) { - /* ??? shouldn't it be newsock instead of newsock_ptr??? */ - closesocket(*key->accept_overlapped.newsock_ptr); - } - break; - } - } - pj_lock_release(ioque->lock); - key->connecting = 0; - } -#endif - return PJ_SUCCESS; -} - -PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key ) -{ - PJ_ASSERT_RETURN(key, NULL); - return key->user_data; -} - -/* - * Poll for events. - */ -PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout) -{ - DWORD dwMsec, dwBytesTransfered, dwKey; - ioqueue_overlapped *ov; - pj_ioqueue_key_t *key; - pj_ssize_t size_status; - BOOL rc; - - PJ_ASSERT_RETURN(ioque, -PJ_EINVAL); - - /* Check the connecting array. */ -#if PJ_HAS_TCP - key = check_connecting(ioque, &size_status); - if (key != NULL) { - key->cb.on_connect_complete(key, (int)size_status); - return 1; - } -#endif - - /* Calculate miliseconds timeout for GetQueuedCompletionStatus */ - dwMsec = timeout ? timeout->sec*1000 + timeout->msec : INFINITE; - - /* Poll for completion status. */ - rc = GetQueuedCompletionStatus(ioque->iocp, &dwBytesTransfered, &dwKey, - (OVERLAPPED**)&ov, dwMsec); - - /* The return value is: - * - nonzero if event was dequeued. - * - zero and ov==NULL if no event was dequeued. - * - zero and ov!=NULL if event for failed I/O was dequeued. - */ - if (ov) { - /* Event was dequeued for either successfull or failed I/O */ - key = (pj_ioqueue_key_t*)dwKey; - size_status = dwBytesTransfered; - switch (ov->operation) { - case PJ_IOQUEUE_OP_READ: - case PJ_IOQUEUE_OP_RECV: - case PJ_IOQUEUE_OP_RECV_FROM: - key->recv_overlapped.operation = 0; - if (key->cb.on_read_complete) - key->cb.on_read_complete(key, size_status); - break; - case PJ_IOQUEUE_OP_WRITE: - case PJ_IOQUEUE_OP_SEND: - case PJ_IOQUEUE_OP_SEND_TO: - key->send_overlapped.operation = 0; - if (key->cb.on_write_complete) - key->cb.on_write_complete(key, size_status); - break; -#if PJ_HAS_TCP - case PJ_IOQUEUE_OP_ACCEPT: - /* special case for accept. */ - ioqueue_on_accept_complete((ioqueue_accept_rec*)ov); - if (key->cb.on_accept_complete) - key->cb.on_accept_complete(key, key->accept_overlapped.newsock, - 0); - break; - case PJ_IOQUEUE_OP_CONNECT: -#endif - case PJ_IOQUEUE_OP_NONE: - pj_assert(0); - break; - } - return 1; - } - - if (GetLastError()==WAIT_TIMEOUT) { - /* Check the connecting array. */ -#if PJ_HAS_TCP - key = check_connecting(ioque, &size_status); - if (key != NULL) { - key->cb.on_connect_complete(key, (int)size_status); - return 1; - } -#endif - return 0; - } - return -1; -} - -/* - * pj_ioqueue_read() - * - * Initiate overlapped ReadFile operation. - */ -PJ_DEF(pj_status_t) pj_ioqueue_read( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - void *buffer, - pj_size_t buflen) -{ - BOOL rc; - DWORD bytesRead; - - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(ioque); - - if (key->recv_overlapped.operation != PJ_IOQUEUE_OP_NONE) { - pj_assert(!"Operation already pending for this descriptor"); - return PJ_EBUSY; - } - - pj_memset(&key->recv_overlapped, 0, sizeof(key->recv_overlapped)); - key->recv_overlapped.operation = PJ_IOQUEUE_OP_READ; - - rc = ReadFile(key->hnd, buffer, buflen, &bytesRead, - &key->recv_overlapped.overlapped); - if (rc == FALSE) { - DWORD dwStatus = GetLastError(); - if (dwStatus==ERROR_IO_PENDING) - return PJ_EPENDING; - else - return PJ_STATUS_FROM_OS(dwStatus); - } else { - /* - * This is workaround to a probable bug in Win2000 (probably NT too). - * Even if 'rc' is TRUE, which indicates operation has completed, - * GetQueuedCompletionStatus still will return the key. - * So as work around, we always return PJ_EPENDING here. - */ - return PJ_EPENDING; - } -} - -/* - * pj_ioqueue_recv() - * - * Initiate overlapped WSARecv() operation. - */ -PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - void *buffer, - pj_size_t buflen, - unsigned flags ) -{ - int rc; - DWORD bytesRead; - DWORD dwFlags = 0; - - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(ioque); - - if (key->recv_overlapped.operation != PJ_IOQUEUE_OP_NONE) { - pj_assert(!"Operation already pending for this socket"); - return PJ_EBUSY; - } - - pj_memset(&key->recv_overlapped, 0, sizeof(key->recv_overlapped)); - key->recv_overlapped.operation = PJ_IOQUEUE_OP_READ; - - key->recv_overlapped.wsabuf.buf = buffer; - key->recv_overlapped.wsabuf.len = buflen; - - dwFlags = flags; - - rc = WSARecv((SOCKET)key->hnd, &key->recv_overlapped.wsabuf, 1, - &bytesRead, &dwFlags, - &key->recv_overlapped.overlapped, NULL); - if (rc == SOCKET_ERROR) { - DWORD dwStatus = WSAGetLastError(); - if (dwStatus==WSA_IO_PENDING) - return PJ_EPENDING; - else - return PJ_STATUS_FROM_OS(dwStatus); - } else { - /* Must always return pending status. - * See comments on pj_ioqueue_read - * return bytesRead; - */ - return PJ_EPENDING; - } -} - -/* - * pj_ioqueue_recvfrom() - * - * Initiate overlapped RecvFrom() operation. - */ -PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - void *buffer, - pj_size_t buflen, - unsigned flags, - pj_sockaddr_t *addr, - int *addrlen) -{ - BOOL rc; - DWORD bytesRead; - DWORD dwFlags; - - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(ioque); - - if (key->recv_overlapped.operation != PJ_IOQUEUE_OP_NONE) { - pj_assert(!"Operation already pending for this socket"); - return PJ_EBUSY; - } - - pj_memset(&key->recv_overlapped, 0, sizeof(key->recv_overlapped)); - key->recv_overlapped.operation = PJ_IOQUEUE_OP_RECV_FROM; - key->recv_overlapped.wsabuf.buf = buffer; - key->recv_overlapped.wsabuf.len = buflen; - dwFlags = flags; - rc = WSARecvFrom((SOCKET)key->hnd, &key->recv_overlapped.wsabuf, 1, - &bytesRead, &dwFlags, - addr, addrlen, - &key->recv_overlapped.overlapped, NULL); - if (rc == SOCKET_ERROR) { - DWORD dwStatus = WSAGetLastError(); - if (dwStatus==WSA_IO_PENDING) - return PJ_EPENDING; - else - return PJ_STATUS_FROM_OS(dwStatus); - } else { - /* Must always return pending status. - * See comments on pj_ioqueue_read - * return bytesRead; - */ - return PJ_EPENDING; - } -} - -/* - * pj_ioqueue_write() - * - * Initiate overlapped WriteFile() operation. - */ -PJ_DEF(pj_status_t) pj_ioqueue_write( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - const void *data, - pj_size_t datalen) -{ - BOOL rc; - DWORD bytesWritten; - - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(ioque); - - if (key->send_overlapped.operation != PJ_IOQUEUE_OP_NONE) { - pj_assert(!"Operation already pending for this descriptor"); - return PJ_EBUSY; - } - - pj_memset(&key->send_overlapped, 0, sizeof(key->send_overlapped)); - key->send_overlapped.operation = PJ_IOQUEUE_OP_WRITE; - rc = WriteFile(key->hnd, data, datalen, &bytesWritten, - &key->send_overlapped.overlapped); - - if (rc == FALSE) { - DWORD dwStatus = GetLastError(); - if (dwStatus==ERROR_IO_PENDING) - return PJ_EPENDING; - else - return PJ_STATUS_FROM_OS(dwStatus); - } else { - /* Must always return pending status. - * See comments on pj_ioqueue_read - * return bytesWritten; - */ - return PJ_EPENDING; - } -} - - -/* - * pj_ioqueue_send() - * - * Initiate overlapped Send operation. - */ -PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - const void *data, - pj_size_t datalen, - unsigned flags ) -{ - int rc; - DWORD bytesWritten; - DWORD dwFlags; - - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(ioque); - - if (key->send_overlapped.operation != PJ_IOQUEUE_OP_NONE) { - pj_assert(!"Operation already pending for this socket"); - return PJ_EBUSY; - } - - pj_memset(&key->send_overlapped, 0, sizeof(key->send_overlapped)); - key->send_overlapped.operation = PJ_IOQUEUE_OP_WRITE; - key->send_overlapped.wsabuf.buf = (void*)data; - key->send_overlapped.wsabuf.len = datalen; - dwFlags = flags; - rc = WSASend((SOCKET)key->hnd, &key->send_overlapped.wsabuf, 1, - &bytesWritten, dwFlags, - &key->send_overlapped.overlapped, NULL); - if (rc == SOCKET_ERROR) { - DWORD dwStatus = WSAGetLastError(); - if (dwStatus==WSA_IO_PENDING) - return PJ_EPENDING; - else - return PJ_STATUS_FROM_OS(dwStatus); - } else { - /* Must always return pending status. - * See comments on pj_ioqueue_read - * return bytesRead; - */ - return PJ_EPENDING; - } -} - - -/* - * pj_ioqueue_sendto() - * - * Initiate overlapped SendTo operation. - */ -PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_t *ioque, - pj_ioqueue_key_t *key, - const void *data, - pj_size_t datalen, - unsigned flags, - const pj_sockaddr_t *addr, - int addrlen) -{ - BOOL rc; - DWORD bytesSent; - DWORD dwFlags; - - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(ioque); - - if (key->send_overlapped.operation != PJ_IOQUEUE_OP_NONE) { - pj_assert(!"Operation already pending for this socket"); - return PJ_EBUSY; - } - - pj_memset(&key->send_overlapped, 0, sizeof(key->send_overlapped)); - key->send_overlapped.operation = PJ_IOQUEUE_OP_SEND_TO; - key->send_overlapped.wsabuf.buf = (char*)data; - key->send_overlapped.wsabuf.len = datalen; - dwFlags = flags; - rc = WSASendTo((SOCKET)key->hnd, &key->send_overlapped.wsabuf, 1, - &bytesSent, dwFlags, addr, - addrlen, &key->send_overlapped.overlapped, NULL); - if (rc == SOCKET_ERROR) { - DWORD dwStatus = WSAGetLastError(); - if (dwStatus==WSA_IO_PENDING) - return PJ_EPENDING; - else - return PJ_STATUS_FROM_OS(dwStatus); - } else { - // Must always return pending status. - // See comments on pj_ioqueue_read - // return bytesSent; - return PJ_EPENDING; - } -} - -#if PJ_HAS_TCP - -/* - * pj_ioqueue_accept() - * - * Initiate overlapped accept() operation. - */ -PJ_DEF(int) pj_ioqueue_accept( pj_ioqueue_t *ioqueue, - pj_ioqueue_key_t *key, - pj_sock_t *new_sock, - pj_sockaddr_t *local, - pj_sockaddr_t *remote, - int *addrlen) -{ - BOOL rc; - DWORD bytesReceived; - pj_status_t status; - - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(ioqueue); - - if (key->accept_overlapped.operation != PJ_IOQUEUE_OP_NONE) { - pj_assert(!"Operation already pending for this socket"); - return PJ_EBUSY; - } - - if (key->accept_overlapped.newsock == PJ_INVALID_SOCKET) { - pj_sock_t sock; - status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &sock); - if (status != PJ_SUCCESS) - return status; - - key->accept_overlapped.newsock = sock; - } - key->accept_overlapped.operation = PJ_IOQUEUE_OP_ACCEPT; - key->accept_overlapped.addrlen = addrlen; - key->accept_overlapped.local = local; - key->accept_overlapped.remote = remote; - key->accept_overlapped.newsock_ptr = new_sock; - pj_memset(&key->accept_overlapped.overlapped, 0, - sizeof(key->accept_overlapped.overlapped)); - - rc = AcceptEx( (SOCKET)key->hnd, (SOCKET)key->accept_overlapped.newsock, - key->accept_overlapped.accept_buf, - 0, ACCEPT_ADDR_LEN, ACCEPT_ADDR_LEN, - &bytesReceived, - &key->accept_overlapped.overlapped); - - if (rc == TRUE) { - ioqueue_on_accept_complete(&key->accept_overlapped); - if (key->cb.on_accept_complete) - key->cb.on_accept_complete(key, key->accept_overlapped.newsock, 0); - return PJ_SUCCESS; - } else { - DWORD dwStatus = WSAGetLastError(); - if (dwStatus==WSA_IO_PENDING) - return PJ_EPENDING; - else - return PJ_STATUS_FROM_OS(dwStatus); - } -} - - -/* - * pj_ioqueue_connect() - * - * Initiate overlapped connect() operation (well, it's non-blocking actually, - * since there's no overlapped version of connect()). - */ -PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue, - pj_ioqueue_key_t *key, - const pj_sockaddr_t *addr, - int addrlen ) -{ - unsigned long optval = 1; - HANDLE hEvent; - - PJ_CHECK_STACK(); - - /* Set socket to non-blocking. */ - if (ioctlsocket((pj_sock_t)key->hnd, FIONBIO, &optval) != 0) { - return PJ_RETURN_OS_ERROR(WSAGetLastError()); - } - - /* Initiate connect() */ - if (connect((pj_sock_t)key->hnd, addr, addrlen) != 0) { - DWORD dwStatus; - dwStatus = WSAGetLastError(); - if (dwStatus != WSAEWOULDBLOCK) { - /* Permanent error */ - return PJ_RETURN_OS_ERROR(dwStatus); - } else { - /* Pending operation. This is what we're looking for. */ - } - } else { - /* Connect has completed immediately! */ - /* Restore to blocking mode. */ - optval = 0; - if (ioctlsocket((pj_sock_t)key->hnd, FIONBIO, &optval) != 0) { - return PJ_RETURN_OS_ERROR(WSAGetLastError()); - } - - key->cb.on_connect_complete(key, 0); - return PJ_SUCCESS; - } - - /* Add to the array of connecting socket to be polled */ - pj_lock_acquire(ioqueue->lock); - - if (ioqueue->connecting_count >= MAXIMUM_WAIT_OBJECTS) { - pj_lock_release(ioqueue->lock); - return PJ_ETOOMANYCONN; - } - - /* Get or create event object. */ - if (ioqueue->event_count) { - hEvent = ioqueue->event_pool[ioqueue->event_count - 1]; - --ioqueue->event_count; - } else { - hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (hEvent == NULL) { - DWORD dwStatus = GetLastError(); - pj_lock_release(ioqueue->lock); - return PJ_STATUS_FROM_OS(dwStatus); - } - } - - /* Mark key as connecting. - * We can't use array index since key can be removed dynamically. - */ - key->connecting = 1; - - /* Associate socket events to the event object. */ - if (WSAEventSelect((pj_sock_t)key->hnd, hEvent, FD_CONNECT) != 0) { - CloseHandle(hEvent); - pj_lock_release(ioqueue->lock); - return PJ_RETURN_OS_ERROR(WSAGetLastError()); - } - - /* Add to array. */ - ioqueue->connecting_keys[ ioqueue->connecting_count ] = key; - ioqueue->connecting_handles[ ioqueue->connecting_count ] = hEvent; - ioqueue->connecting_count++; - - pj_lock_release(ioqueue->lock); - - return PJ_EPENDING; -} -#endif /* #if PJ_HAS_TCP */ - +/* $Header: /pjproject-0.3/pjlib/src/pj/ioqueue_winnt.c 11 10/29/05 11:31a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/ioqueue_winnt.c $ + * + * 11 10/29/05 11:31a Bennylp + * Changed accept and lock. + * + * 10 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 9 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0 +# include +#elif defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0 +# include +#endif + +#if defined(PJ_HAS_MSWSOCK_H) && PJ_HAS_MSWSOCK_H != 0 +# include +#endif + + +#define ACCEPT_ADDR_LEN (sizeof(pj_sockaddr_in)+20) + +/* + * OVERLAP structure for send and receive. + */ +typedef struct ioqueue_overlapped +{ + WSAOVERLAPPED overlapped; + pj_ioqueue_operation_e operation; + WSABUF wsabuf; +} ioqueue_overlapped; + +#if PJ_HAS_TCP +/* + * OVERLAP structure for accept. + */ +typedef struct ioqueue_accept_rec +{ + WSAOVERLAPPED overlapped; + pj_ioqueue_operation_e operation; + pj_sock_t newsock; + pj_sock_t *newsock_ptr; + int *addrlen; + void *remote; + void *local; + char accept_buf[2 * ACCEPT_ADDR_LEN]; +} ioqueue_accept_rec; +#endif + +/* + * Structure for individual socket. + */ +struct pj_ioqueue_key_t +{ + HANDLE hnd; + void *user_data; + ioqueue_overlapped recv_overlapped; + ioqueue_overlapped send_overlapped; +#if PJ_HAS_TCP + int connecting; + ioqueue_accept_rec accept_overlapped; +#endif + pj_ioqueue_callback cb; +}; + +/* + * IO Queue structure. + */ +struct pj_ioqueue_t +{ + HANDLE iocp; + pj_lock_t *lock; + pj_bool_t auto_delete_lock; + unsigned event_count; + HANDLE event_pool[MAXIMUM_WAIT_OBJECTS+1]; +#if PJ_HAS_TCP + unsigned connecting_count; + HANDLE connecting_handles[MAXIMUM_WAIT_OBJECTS+1]; + pj_ioqueue_key_t *connecting_keys[MAXIMUM_WAIT_OBJECTS+1]; +#endif +}; + + +#if PJ_HAS_TCP +/* + * Process the socket when the overlapped accept() completed. + */ +static void ioqueue_on_accept_complete(ioqueue_accept_rec *accept_overlapped) +{ + struct sockaddr *local; + struct sockaddr *remote; + int locallen, remotelen; + + PJ_CHECK_STACK(); + + /* Operation complete immediately. */ + GetAcceptExSockaddrs( accept_overlapped->accept_buf, + 0, + ACCEPT_ADDR_LEN, + ACCEPT_ADDR_LEN, + &local, + &locallen, + &remote, + &remotelen); + pj_memcpy(accept_overlapped->local, local, locallen); + pj_memcpy(accept_overlapped->remote, remote, locallen); + *accept_overlapped->addrlen = locallen; + if (accept_overlapped->newsock_ptr) + *accept_overlapped->newsock_ptr = accept_overlapped->newsock; + accept_overlapped->operation = 0; + accept_overlapped->newsock = PJ_INVALID_SOCKET; +} + +static void erase_connecting_socket( pj_ioqueue_t *ioqueue, unsigned pos) +{ + pj_ioqueue_key_t *key = ioqueue->connecting_keys[pos]; + HANDLE hEvent = ioqueue->connecting_handles[pos]; + unsigned long optval; + + /* Remove key from array of connecting handles. */ + pj_array_erase(ioqueue->connecting_keys, sizeof(key), + ioqueue->connecting_count, pos); + pj_array_erase(ioqueue->connecting_handles, sizeof(HANDLE), + ioqueue->connecting_count, pos); + --ioqueue->connecting_count; + + /* Disassociate the socket from the event. */ + WSAEventSelect((pj_sock_t)key->hnd, hEvent, 0); + + /* Put event object to pool. */ + if (ioqueue->event_count < MAXIMUM_WAIT_OBJECTS) { + ioqueue->event_pool[ioqueue->event_count++] = hEvent; + } else { + /* Shouldn't happen. There should be no more pending connections + * than max. + */ + pj_assert(0); + CloseHandle(hEvent); + } + + /* Set socket to blocking again. */ + optval = 0; + if (ioctlsocket((pj_sock_t)key->hnd, FIONBIO, &optval) != 0) { + DWORD dwStatus; + dwStatus = WSAGetLastError(); + } +} + +/* + * Poll for the completion of non-blocking connect(). + * If there's a completion, the function return the key of the completed + * socket, and 'result' argument contains the connect() result. If connect() + * succeeded, 'result' will have value zero, otherwise will have the error + * code. + */ +static pj_ioqueue_key_t *check_connecting( pj_ioqueue_t *ioqueue, + pj_ssize_t *connect_err ) +{ + pj_ioqueue_key_t *key = NULL; + + if (ioqueue->connecting_count) { + DWORD result; + + pj_lock_acquire(ioqueue->lock); + result = WaitForMultipleObjects(ioqueue->connecting_count, + ioqueue->connecting_handles, + FALSE, 0); + if (result >= WAIT_OBJECT_0 && + result < WAIT_OBJECT_0+ioqueue->connecting_count) + { + WSANETWORKEVENTS net_events; + + /* Got completed connect(). */ + unsigned pos = result - WAIT_OBJECT_0; + key = ioqueue->connecting_keys[pos]; + + /* See whether connect has succeeded. */ + WSAEnumNetworkEvents((pj_sock_t)key->hnd, + ioqueue->connecting_handles[pos], + &net_events); + *connect_err = net_events.iErrorCode[FD_CONNECT_BIT]; + + /* Erase socket from pending connect. */ + erase_connecting_socket(ioqueue, pos); + } + pj_lock_release(ioqueue->lock); + } + return key; +} +#endif + + +PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, + pj_size_t max_fd, + int max_threads, + pj_ioqueue_t **ioqueue) +{ + pj_ioqueue_t *ioq; + pj_status_t rc; + + PJ_UNUSED_ARG(max_fd); + PJ_ASSERT_RETURN(pool && ioqueue, PJ_EINVAL); + + ioq = pj_pool_zalloc(pool, sizeof(*ioq)); + ioq->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, max_threads); + if (ioq->iocp == NULL) + return PJ_RETURN_OS_ERROR(GetLastError()); + + rc = pj_lock_create_simple_mutex(pool, NULL, &ioq->lock); + if (rc != PJ_SUCCESS) { + CloseHandle(ioq->iocp); + return rc; + } + + ioq->auto_delete_lock = PJ_TRUE; + + *ioqueue = ioq; + + PJ_LOG(4, ("pjlib", "WinNT IOCP I/O Queue created (%p)", ioq)); + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioque ) +{ + unsigned i; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(ioque, PJ_EINVAL); + + /* Destroy events in the pool */ + for (i=0; ievent_count; ++i) { + CloseHandle(ioque->event_pool[i]); + } + ioque->event_count = 0; + + if (ioque->auto_delete_lock) + pj_lock_destroy(ioque->lock); + + if (CloseHandle(ioque->iocp) == TRUE) + return PJ_SUCCESS; + else + return PJ_RETURN_OS_ERROR(GetLastError()); +} + +PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, + pj_lock_t *lock, + pj_bool_t auto_delete ) +{ + PJ_ASSERT_RETURN(ioque && lock, PJ_EINVAL); + + if (ioque->auto_delete_lock) { + pj_lock_destroy(ioque->lock); + } + + ioque->lock = lock; + ioque->auto_delete_lock = auto_delete; + + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool, + pj_ioqueue_t *ioque, + pj_sock_t hnd, + void *user_data, + const pj_ioqueue_callback *cb, + pj_ioqueue_key_t **key ) +{ + HANDLE hioq; + pj_ioqueue_key_t *rec; + + PJ_ASSERT_RETURN(pool && ioque && cb && key, PJ_EINVAL); + + rec = pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t)); + rec->hnd = (HANDLE)hnd; + rec->user_data = user_data; + pj_memcpy(&rec->cb, cb, sizeof(pj_ioqueue_callback)); +#if PJ_HAS_TCP + rec->accept_overlapped.newsock = PJ_INVALID_SOCKET; +#endif + hioq = CreateIoCompletionPort((HANDLE)hnd, ioque->iocp, (DWORD)rec, 0); + if (!hioq) { + return PJ_RETURN_OS_ERROR(GetLastError()); + } + + *key = rec; + return PJ_SUCCESS; +} + + + +PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key ) +{ + PJ_ASSERT_RETURN(ioque && key, PJ_EINVAL); + +#if PJ_HAS_TCP + if (key->connecting) { + unsigned pos; + + /* Erase from connecting_handles */ + pj_lock_acquire(ioque->lock); + for (pos=0; pos < ioque->connecting_count; ++pos) { + if (ioque->connecting_keys[pos] == key) { + erase_connecting_socket(ioque, pos); + if (key->accept_overlapped.newsock_ptr) { + /* ??? shouldn't it be newsock instead of newsock_ptr??? */ + closesocket(*key->accept_overlapped.newsock_ptr); + } + break; + } + } + pj_lock_release(ioque->lock); + key->connecting = 0; + } +#endif + return PJ_SUCCESS; +} + +PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key ) +{ + PJ_ASSERT_RETURN(key, NULL); + return key->user_data; +} + +/* + * Poll for events. + */ +PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout) +{ + DWORD dwMsec, dwBytesTransfered, dwKey; + ioqueue_overlapped *ov; + pj_ioqueue_key_t *key; + pj_ssize_t size_status; + BOOL rc; + + PJ_ASSERT_RETURN(ioque, -PJ_EINVAL); + + /* Check the connecting array. */ +#if PJ_HAS_TCP + key = check_connecting(ioque, &size_status); + if (key != NULL) { + key->cb.on_connect_complete(key, (int)size_status); + return 1; + } +#endif + + /* Calculate miliseconds timeout for GetQueuedCompletionStatus */ + dwMsec = timeout ? timeout->sec*1000 + timeout->msec : INFINITE; + + /* Poll for completion status. */ + rc = GetQueuedCompletionStatus(ioque->iocp, &dwBytesTransfered, &dwKey, + (OVERLAPPED**)&ov, dwMsec); + + /* The return value is: + * - nonzero if event was dequeued. + * - zero and ov==NULL if no event was dequeued. + * - zero and ov!=NULL if event for failed I/O was dequeued. + */ + if (ov) { + /* Event was dequeued for either successfull or failed I/O */ + key = (pj_ioqueue_key_t*)dwKey; + size_status = dwBytesTransfered; + switch (ov->operation) { + case PJ_IOQUEUE_OP_READ: + case PJ_IOQUEUE_OP_RECV: + case PJ_IOQUEUE_OP_RECV_FROM: + key->recv_overlapped.operation = 0; + if (key->cb.on_read_complete) + key->cb.on_read_complete(key, size_status); + break; + case PJ_IOQUEUE_OP_WRITE: + case PJ_IOQUEUE_OP_SEND: + case PJ_IOQUEUE_OP_SEND_TO: + key->send_overlapped.operation = 0; + if (key->cb.on_write_complete) + key->cb.on_write_complete(key, size_status); + break; +#if PJ_HAS_TCP + case PJ_IOQUEUE_OP_ACCEPT: + /* special case for accept. */ + ioqueue_on_accept_complete((ioqueue_accept_rec*)ov); + if (key->cb.on_accept_complete) + key->cb.on_accept_complete(key, key->accept_overlapped.newsock, + 0); + break; + case PJ_IOQUEUE_OP_CONNECT: +#endif + case PJ_IOQUEUE_OP_NONE: + pj_assert(0); + break; + } + return 1; + } + + if (GetLastError()==WAIT_TIMEOUT) { + /* Check the connecting array. */ +#if PJ_HAS_TCP + key = check_connecting(ioque, &size_status); + if (key != NULL) { + key->cb.on_connect_complete(key, (int)size_status); + return 1; + } +#endif + return 0; + } + return -1; +} + +/* + * pj_ioqueue_read() + * + * Initiate overlapped ReadFile operation. + */ +PJ_DEF(pj_status_t) pj_ioqueue_read( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + void *buffer, + pj_size_t buflen) +{ + BOOL rc; + DWORD bytesRead; + + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(ioque); + + if (key->recv_overlapped.operation != PJ_IOQUEUE_OP_NONE) { + pj_assert(!"Operation already pending for this descriptor"); + return PJ_EBUSY; + } + + pj_memset(&key->recv_overlapped, 0, sizeof(key->recv_overlapped)); + key->recv_overlapped.operation = PJ_IOQUEUE_OP_READ; + + rc = ReadFile(key->hnd, buffer, buflen, &bytesRead, + &key->recv_overlapped.overlapped); + if (rc == FALSE) { + DWORD dwStatus = GetLastError(); + if (dwStatus==ERROR_IO_PENDING) + return PJ_EPENDING; + else + return PJ_STATUS_FROM_OS(dwStatus); + } else { + /* + * This is workaround to a probable bug in Win2000 (probably NT too). + * Even if 'rc' is TRUE, which indicates operation has completed, + * GetQueuedCompletionStatus still will return the key. + * So as work around, we always return PJ_EPENDING here. + */ + return PJ_EPENDING; + } +} + +/* + * pj_ioqueue_recv() + * + * Initiate overlapped WSARecv() operation. + */ +PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + void *buffer, + pj_size_t buflen, + unsigned flags ) +{ + int rc; + DWORD bytesRead; + DWORD dwFlags = 0; + + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(ioque); + + if (key->recv_overlapped.operation != PJ_IOQUEUE_OP_NONE) { + pj_assert(!"Operation already pending for this socket"); + return PJ_EBUSY; + } + + pj_memset(&key->recv_overlapped, 0, sizeof(key->recv_overlapped)); + key->recv_overlapped.operation = PJ_IOQUEUE_OP_READ; + + key->recv_overlapped.wsabuf.buf = buffer; + key->recv_overlapped.wsabuf.len = buflen; + + dwFlags = flags; + + rc = WSARecv((SOCKET)key->hnd, &key->recv_overlapped.wsabuf, 1, + &bytesRead, &dwFlags, + &key->recv_overlapped.overlapped, NULL); + if (rc == SOCKET_ERROR) { + DWORD dwStatus = WSAGetLastError(); + if (dwStatus==WSA_IO_PENDING) + return PJ_EPENDING; + else + return PJ_STATUS_FROM_OS(dwStatus); + } else { + /* Must always return pending status. + * See comments on pj_ioqueue_read + * return bytesRead; + */ + return PJ_EPENDING; + } +} + +/* + * pj_ioqueue_recvfrom() + * + * Initiate overlapped RecvFrom() operation. + */ +PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + void *buffer, + pj_size_t buflen, + unsigned flags, + pj_sockaddr_t *addr, + int *addrlen) +{ + BOOL rc; + DWORD bytesRead; + DWORD dwFlags; + + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(ioque); + + if (key->recv_overlapped.operation != PJ_IOQUEUE_OP_NONE) { + pj_assert(!"Operation already pending for this socket"); + return PJ_EBUSY; + } + + pj_memset(&key->recv_overlapped, 0, sizeof(key->recv_overlapped)); + key->recv_overlapped.operation = PJ_IOQUEUE_OP_RECV_FROM; + key->recv_overlapped.wsabuf.buf = buffer; + key->recv_overlapped.wsabuf.len = buflen; + dwFlags = flags; + rc = WSARecvFrom((SOCKET)key->hnd, &key->recv_overlapped.wsabuf, 1, + &bytesRead, &dwFlags, + addr, addrlen, + &key->recv_overlapped.overlapped, NULL); + if (rc == SOCKET_ERROR) { + DWORD dwStatus = WSAGetLastError(); + if (dwStatus==WSA_IO_PENDING) + return PJ_EPENDING; + else + return PJ_STATUS_FROM_OS(dwStatus); + } else { + /* Must always return pending status. + * See comments on pj_ioqueue_read + * return bytesRead; + */ + return PJ_EPENDING; + } +} + +/* + * pj_ioqueue_write() + * + * Initiate overlapped WriteFile() operation. + */ +PJ_DEF(pj_status_t) pj_ioqueue_write( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + const void *data, + pj_size_t datalen) +{ + BOOL rc; + DWORD bytesWritten; + + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(ioque); + + if (key->send_overlapped.operation != PJ_IOQUEUE_OP_NONE) { + pj_assert(!"Operation already pending for this descriptor"); + return PJ_EBUSY; + } + + pj_memset(&key->send_overlapped, 0, sizeof(key->send_overlapped)); + key->send_overlapped.operation = PJ_IOQUEUE_OP_WRITE; + rc = WriteFile(key->hnd, data, datalen, &bytesWritten, + &key->send_overlapped.overlapped); + + if (rc == FALSE) { + DWORD dwStatus = GetLastError(); + if (dwStatus==ERROR_IO_PENDING) + return PJ_EPENDING; + else + return PJ_STATUS_FROM_OS(dwStatus); + } else { + /* Must always return pending status. + * See comments on pj_ioqueue_read + * return bytesWritten; + */ + return PJ_EPENDING; + } +} + + +/* + * pj_ioqueue_send() + * + * Initiate overlapped Send operation. + */ +PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + const void *data, + pj_size_t datalen, + unsigned flags ) +{ + int rc; + DWORD bytesWritten; + DWORD dwFlags; + + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(ioque); + + if (key->send_overlapped.operation != PJ_IOQUEUE_OP_NONE) { + pj_assert(!"Operation already pending for this socket"); + return PJ_EBUSY; + } + + pj_memset(&key->send_overlapped, 0, sizeof(key->send_overlapped)); + key->send_overlapped.operation = PJ_IOQUEUE_OP_WRITE; + key->send_overlapped.wsabuf.buf = (void*)data; + key->send_overlapped.wsabuf.len = datalen; + dwFlags = flags; + rc = WSASend((SOCKET)key->hnd, &key->send_overlapped.wsabuf, 1, + &bytesWritten, dwFlags, + &key->send_overlapped.overlapped, NULL); + if (rc == SOCKET_ERROR) { + DWORD dwStatus = WSAGetLastError(); + if (dwStatus==WSA_IO_PENDING) + return PJ_EPENDING; + else + return PJ_STATUS_FROM_OS(dwStatus); + } else { + /* Must always return pending status. + * See comments on pj_ioqueue_read + * return bytesRead; + */ + return PJ_EPENDING; + } +} + + +/* + * pj_ioqueue_sendto() + * + * Initiate overlapped SendTo operation. + */ +PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_t *ioque, + pj_ioqueue_key_t *key, + const void *data, + pj_size_t datalen, + unsigned flags, + const pj_sockaddr_t *addr, + int addrlen) +{ + BOOL rc; + DWORD bytesSent; + DWORD dwFlags; + + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(ioque); + + if (key->send_overlapped.operation != PJ_IOQUEUE_OP_NONE) { + pj_assert(!"Operation already pending for this socket"); + return PJ_EBUSY; + } + + pj_memset(&key->send_overlapped, 0, sizeof(key->send_overlapped)); + key->send_overlapped.operation = PJ_IOQUEUE_OP_SEND_TO; + key->send_overlapped.wsabuf.buf = (char*)data; + key->send_overlapped.wsabuf.len = datalen; + dwFlags = flags; + rc = WSASendTo((SOCKET)key->hnd, &key->send_overlapped.wsabuf, 1, + &bytesSent, dwFlags, addr, + addrlen, &key->send_overlapped.overlapped, NULL); + if (rc == SOCKET_ERROR) { + DWORD dwStatus = WSAGetLastError(); + if (dwStatus==WSA_IO_PENDING) + return PJ_EPENDING; + else + return PJ_STATUS_FROM_OS(dwStatus); + } else { + // Must always return pending status. + // See comments on pj_ioqueue_read + // return bytesSent; + return PJ_EPENDING; + } +} + +#if PJ_HAS_TCP + +/* + * pj_ioqueue_accept() + * + * Initiate overlapped accept() operation. + */ +PJ_DEF(int) pj_ioqueue_accept( pj_ioqueue_t *ioqueue, + pj_ioqueue_key_t *key, + pj_sock_t *new_sock, + pj_sockaddr_t *local, + pj_sockaddr_t *remote, + int *addrlen) +{ + BOOL rc; + DWORD bytesReceived; + pj_status_t status; + + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(ioqueue); + + if (key->accept_overlapped.operation != PJ_IOQUEUE_OP_NONE) { + pj_assert(!"Operation already pending for this socket"); + return PJ_EBUSY; + } + + if (key->accept_overlapped.newsock == PJ_INVALID_SOCKET) { + pj_sock_t sock; + status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &sock); + if (status != PJ_SUCCESS) + return status; + + key->accept_overlapped.newsock = sock; + } + key->accept_overlapped.operation = PJ_IOQUEUE_OP_ACCEPT; + key->accept_overlapped.addrlen = addrlen; + key->accept_overlapped.local = local; + key->accept_overlapped.remote = remote; + key->accept_overlapped.newsock_ptr = new_sock; + pj_memset(&key->accept_overlapped.overlapped, 0, + sizeof(key->accept_overlapped.overlapped)); + + rc = AcceptEx( (SOCKET)key->hnd, (SOCKET)key->accept_overlapped.newsock, + key->accept_overlapped.accept_buf, + 0, ACCEPT_ADDR_LEN, ACCEPT_ADDR_LEN, + &bytesReceived, + &key->accept_overlapped.overlapped); + + if (rc == TRUE) { + ioqueue_on_accept_complete(&key->accept_overlapped); + if (key->cb.on_accept_complete) + key->cb.on_accept_complete(key, key->accept_overlapped.newsock, 0); + return PJ_SUCCESS; + } else { + DWORD dwStatus = WSAGetLastError(); + if (dwStatus==WSA_IO_PENDING) + return PJ_EPENDING; + else + return PJ_STATUS_FROM_OS(dwStatus); + } +} + + +/* + * pj_ioqueue_connect() + * + * Initiate overlapped connect() operation (well, it's non-blocking actually, + * since there's no overlapped version of connect()). + */ +PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue, + pj_ioqueue_key_t *key, + const pj_sockaddr_t *addr, + int addrlen ) +{ + unsigned long optval = 1; + HANDLE hEvent; + + PJ_CHECK_STACK(); + + /* Set socket to non-blocking. */ + if (ioctlsocket((pj_sock_t)key->hnd, FIONBIO, &optval) != 0) { + return PJ_RETURN_OS_ERROR(WSAGetLastError()); + } + + /* Initiate connect() */ + if (connect((pj_sock_t)key->hnd, addr, addrlen) != 0) { + DWORD dwStatus; + dwStatus = WSAGetLastError(); + if (dwStatus != WSAEWOULDBLOCK) { + /* Permanent error */ + return PJ_RETURN_OS_ERROR(dwStatus); + } else { + /* Pending operation. This is what we're looking for. */ + } + } else { + /* Connect has completed immediately! */ + /* Restore to blocking mode. */ + optval = 0; + if (ioctlsocket((pj_sock_t)key->hnd, FIONBIO, &optval) != 0) { + return PJ_RETURN_OS_ERROR(WSAGetLastError()); + } + + key->cb.on_connect_complete(key, 0); + return PJ_SUCCESS; + } + + /* Add to the array of connecting socket to be polled */ + pj_lock_acquire(ioqueue->lock); + + if (ioqueue->connecting_count >= MAXIMUM_WAIT_OBJECTS) { + pj_lock_release(ioqueue->lock); + return PJ_ETOOMANYCONN; + } + + /* Get or create event object. */ + if (ioqueue->event_count) { + hEvent = ioqueue->event_pool[ioqueue->event_count - 1]; + --ioqueue->event_count; + } else { + hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (hEvent == NULL) { + DWORD dwStatus = GetLastError(); + pj_lock_release(ioqueue->lock); + return PJ_STATUS_FROM_OS(dwStatus); + } + } + + /* Mark key as connecting. + * We can't use array index since key can be removed dynamically. + */ + key->connecting = 1; + + /* Associate socket events to the event object. */ + if (WSAEventSelect((pj_sock_t)key->hnd, hEvent, FD_CONNECT) != 0) { + CloseHandle(hEvent); + pj_lock_release(ioqueue->lock); + return PJ_RETURN_OS_ERROR(WSAGetLastError()); + } + + /* Add to array. */ + ioqueue->connecting_keys[ ioqueue->connecting_count ] = key; + ioqueue->connecting_handles[ ioqueue->connecting_count ] = hEvent; + ioqueue->connecting_count++; + + pj_lock_release(ioqueue->lock); + + return PJ_EPENDING; +} +#endif /* #if PJ_HAS_TCP */ + diff --git a/pjlib/src/pj/list.c b/pjlib/src/pj/list.c index 82b9e83a..eef10f5d 100644 --- a/pjlib/src/pj/list.c +++ b/pjlib/src/pj/list.c @@ -1,18 +1,18 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/list.c 5 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/list.c $ - * - * 5 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 4 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include - -#if !PJ_FUNCTIONS_ARE_INLINED -# include -#endif - - +/* $Header: /pjproject-0.3/pjlib/src/pj/list.c 5 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/list.c $ + * + * 5 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 4 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include + +#if !PJ_FUNCTIONS_ARE_INLINED +# include +#endif + + diff --git a/pjlib/src/pj/lock.c b/pjlib/src/pj/lock.c index 10b967a8..69d587d5 100644 --- a/pjlib/src/pj/lock.c +++ b/pjlib/src/pj/lock.c @@ -1,190 +1,190 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/lock.c 3 10/29/05 11:51a Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pj/lock.c $ - * - * 3 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 10/05/05 6:35p Bennylp - * Created. - */ -#include -#include -#include -#include -#include -#include - - -typedef void LOCK_OBJ; - -/* - * Lock structure. - */ -struct pj_lock_t -{ - LOCK_OBJ *lock_object; - - pj_status_t (*acquire) (LOCK_OBJ*); - pj_status_t (*tryacquire) (LOCK_OBJ*); - pj_status_t (*release) (LOCK_OBJ*); - pj_status_t (*destroy) (LOCK_OBJ*); -}; - -typedef pj_status_t (*FPTR)(LOCK_OBJ*); - -/****************************************************************************** - * Implementation of lock object with mutex. - */ -static pj_lock_t mutex_lock_template = -{ - NULL, - (FPTR) &pj_mutex_lock, - (FPTR) &pj_mutex_trylock, - (FPTR) &pj_mutex_unlock, - (FPTR) &pj_mutex_destroy -}; - -static pj_status_t create_mutex_lock( pj_pool_t *pool, - const char *name, - int type, - pj_lock_t **lock ) -{ - pj_lock_t *p_lock; - pj_status_t rc; - - PJ_ASSERT_RETURN(pool && lock, PJ_EINVAL); - - p_lock = pj_pool_alloc(pool, sizeof(pj_lock_t)); - if (!p_lock) - return PJ_ENOMEM; - - pj_memcpy(p_lock, &mutex_lock_template, sizeof(pj_lock_t)); - rc = pj_mutex_create(pool, name, type, (pj_mutex_t**)&p_lock->lock_object); - if (rc != PJ_SUCCESS) - return rc; - - *lock = p_lock; - return PJ_SUCCESS; -} - - -PJ_DEF(pj_status_t) pj_lock_create_simple_mutex( pj_pool_t *pool, - const char *name, - pj_lock_t **lock ) -{ - return create_mutex_lock(pool, name, PJ_MUTEX_SIMPLE, lock); -} - -PJ_DEF(pj_status_t) pj_lock_create_recursive_mutex( pj_pool_t *pool, - const char *name, - pj_lock_t **lock ) -{ - return create_mutex_lock(pool, name, PJ_MUTEX_RECURSE, lock); -} - - -/****************************************************************************** - * Implementation of NULL lock object. - */ -static pj_status_t null_op(void *arg) -{ - PJ_UNUSED_ARG(arg); - return PJ_SUCCESS; -} - -static pj_lock_t null_lock_template = -{ - NULL, - &null_op, - &null_op, - &null_op, - &null_op -}; - -PJ_DEF(pj_status_t) pj_lock_create_null_mutex( pj_pool_t *pool, - const char *name, - pj_lock_t **lock ) -{ - PJ_UNUSED_ARG(name); - PJ_UNUSED_ARG(pool); - - PJ_ASSERT_RETURN(lock, PJ_EINVAL); - - *lock = &null_lock_template; - return PJ_SUCCESS; -} - - -/****************************************************************************** - * Implementation of semaphore lock object. - */ -#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 - -static pj_lock_t sem_lock_template = -{ - NULL, - (FPTR) &pj_sem_wait, - (FPTR) &pj_sem_trywait, - (FPTR) &pj_sem_post, - (FPTR) &pj_sem_destroy -}; - -PJ_DEF(pj_status_t) pj_lock_create_semaphore( pj_pool_t *pool, - const char *name, - unsigned initial, - unsigned max, - pj_lock_t **lock ) -{ - pj_lock_t *p_lock; - pj_status_t rc; - - PJ_ASSERT_RETURN(pool && lock, PJ_EINVAL); - - p_lock = pj_pool_alloc(pool, sizeof(pj_lock_t)); - if (!p_lock) - return PJ_ENOMEM; - - pj_memcpy(p_lock, &sem_lock_template, sizeof(pj_lock_t)); - rc = pj_sem_create( pool, name, initial, max, - (pj_sem_t**)&p_lock->lock_object); - if (rc != PJ_SUCCESS) - return rc; - - *lock = p_lock; - - return PJ_SUCCESS; -} - - -#endif /* PJ_HAS_SEMAPHORE */ - - -PJ_DEF(pj_status_t) pj_lock_acquire( pj_lock_t *lock ) -{ - PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL); - return (*lock->acquire)(lock->lock_object); -} - -PJ_DEF(pj_status_t) pj_lock_tryacquire( pj_lock_t *lock ) -{ - PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL); - return (*lock->tryacquire)(lock->lock_object); -} - -PJ_DEF(pj_status_t) pj_lock_release( pj_lock_t *lock ) -{ - PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL); - return (*lock->release)(lock->lock_object); -} - -PJ_DEF(pj_status_t) pj_lock_destroy( pj_lock_t *lock ) -{ - PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL); - return (*lock->destroy)(lock->lock_object); -} - +/* $Header: /pjproject-0.3/pjlib/src/pj/lock.c 3 10/29/05 11:51a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pj/lock.c $ + * + * 3 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 10/05/05 6:35p Bennylp + * Created. + */ +#include +#include +#include +#include +#include +#include + + +typedef void LOCK_OBJ; + +/* + * Lock structure. + */ +struct pj_lock_t +{ + LOCK_OBJ *lock_object; + + pj_status_t (*acquire) (LOCK_OBJ*); + pj_status_t (*tryacquire) (LOCK_OBJ*); + pj_status_t (*release) (LOCK_OBJ*); + pj_status_t (*destroy) (LOCK_OBJ*); +}; + +typedef pj_status_t (*FPTR)(LOCK_OBJ*); + +/****************************************************************************** + * Implementation of lock object with mutex. + */ +static pj_lock_t mutex_lock_template = +{ + NULL, + (FPTR) &pj_mutex_lock, + (FPTR) &pj_mutex_trylock, + (FPTR) &pj_mutex_unlock, + (FPTR) &pj_mutex_destroy +}; + +static pj_status_t create_mutex_lock( pj_pool_t *pool, + const char *name, + int type, + pj_lock_t **lock ) +{ + pj_lock_t *p_lock; + pj_status_t rc; + + PJ_ASSERT_RETURN(pool && lock, PJ_EINVAL); + + p_lock = pj_pool_alloc(pool, sizeof(pj_lock_t)); + if (!p_lock) + return PJ_ENOMEM; + + pj_memcpy(p_lock, &mutex_lock_template, sizeof(pj_lock_t)); + rc = pj_mutex_create(pool, name, type, (pj_mutex_t**)&p_lock->lock_object); + if (rc != PJ_SUCCESS) + return rc; + + *lock = p_lock; + return PJ_SUCCESS; +} + + +PJ_DEF(pj_status_t) pj_lock_create_simple_mutex( pj_pool_t *pool, + const char *name, + pj_lock_t **lock ) +{ + return create_mutex_lock(pool, name, PJ_MUTEX_SIMPLE, lock); +} + +PJ_DEF(pj_status_t) pj_lock_create_recursive_mutex( pj_pool_t *pool, + const char *name, + pj_lock_t **lock ) +{ + return create_mutex_lock(pool, name, PJ_MUTEX_RECURSE, lock); +} + + +/****************************************************************************** + * Implementation of NULL lock object. + */ +static pj_status_t null_op(void *arg) +{ + PJ_UNUSED_ARG(arg); + return PJ_SUCCESS; +} + +static pj_lock_t null_lock_template = +{ + NULL, + &null_op, + &null_op, + &null_op, + &null_op +}; + +PJ_DEF(pj_status_t) pj_lock_create_null_mutex( pj_pool_t *pool, + const char *name, + pj_lock_t **lock ) +{ + PJ_UNUSED_ARG(name); + PJ_UNUSED_ARG(pool); + + PJ_ASSERT_RETURN(lock, PJ_EINVAL); + + *lock = &null_lock_template; + return PJ_SUCCESS; +} + + +/****************************************************************************** + * Implementation of semaphore lock object. + */ +#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 + +static pj_lock_t sem_lock_template = +{ + NULL, + (FPTR) &pj_sem_wait, + (FPTR) &pj_sem_trywait, + (FPTR) &pj_sem_post, + (FPTR) &pj_sem_destroy +}; + +PJ_DEF(pj_status_t) pj_lock_create_semaphore( pj_pool_t *pool, + const char *name, + unsigned initial, + unsigned max, + pj_lock_t **lock ) +{ + pj_lock_t *p_lock; + pj_status_t rc; + + PJ_ASSERT_RETURN(pool && lock, PJ_EINVAL); + + p_lock = pj_pool_alloc(pool, sizeof(pj_lock_t)); + if (!p_lock) + return PJ_ENOMEM; + + pj_memcpy(p_lock, &sem_lock_template, sizeof(pj_lock_t)); + rc = pj_sem_create( pool, name, initial, max, + (pj_sem_t**)&p_lock->lock_object); + if (rc != PJ_SUCCESS) + return rc; + + *lock = p_lock; + + return PJ_SUCCESS; +} + + +#endif /* PJ_HAS_SEMAPHORE */ + + +PJ_DEF(pj_status_t) pj_lock_acquire( pj_lock_t *lock ) +{ + PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL); + return (*lock->acquire)(lock->lock_object); +} + +PJ_DEF(pj_status_t) pj_lock_tryacquire( pj_lock_t *lock ) +{ + PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL); + return (*lock->tryacquire)(lock->lock_object); +} + +PJ_DEF(pj_status_t) pj_lock_release( pj_lock_t *lock ) +{ + PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL); + return (*lock->release)(lock->lock_object); +} + +PJ_DEF(pj_status_t) pj_lock_destroy( pj_lock_t *lock ) +{ + PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL); + return (*lock->destroy)(lock->lock_object); +} + diff --git a/pjlib/src/pj/log.c b/pjlib/src/pj/log.c index 7f79e55c..59d58b2c 100644 --- a/pjlib/src/pj/log.c +++ b/pjlib/src/pj/log.c @@ -1,217 +1,217 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/log.c 7 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/log.c $ - * - * 7 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 6 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include -#include -#include -#include - -#if PJ_LOG_MAX_LEVEL >= 1 - -static int log_max_level = PJ_LOG_MAX_LEVEL; -static pj_log_func *log_writer = &pj_log_write; -static unsigned log_decor = PJ_LOG_HAS_TIME | PJ_LOG_HAS_MICRO_SEC | - PJ_LOG_HAS_SENDER | PJ_LOG_HAS_NEWLINE; - -#if PJ_LOG_USE_STACK_BUFFER==0 -static char log_buffer[PJ_LOG_MAX_SIZE]; -#endif - -PJ_DEF(void) pj_log_set_decor(unsigned decor) -{ - log_decor = decor; -} - -PJ_DEF(unsigned) pj_log_get_decor(void) -{ - return log_decor; -} - -PJ_DEF(void) pj_log_set_level(int level) -{ - log_max_level = level; -} - -PJ_DEF(int) pj_log_get_level(void) -{ - return log_max_level; -} - -PJ_DEF(void) pj_log_set_log_func( pj_log_func *func ) -{ - log_writer = func; -} - -PJ_DEF(pj_log_func*) pj_log_get_log_func(void) -{ - return log_writer; -} - -static void pj_log(const char *sender, int level, - const char *format, va_list marker) -{ - pj_time_val now; - pj_parsed_time ptime; - char *pre; -#if PJ_LOG_USE_STACK_BUFFER - char log_buffer[PJ_LOG_MAX_SIZE]; -#endif - int len; - - PJ_CHECK_STACK(); - - if (level > log_max_level) - return; - - /* Get current date/time. */ - pj_gettimeofday(&now); - pj_time_decode(&now, &ptime); - - pre = log_buffer; - if (log_decor & PJ_LOG_HAS_DAY_NAME) { - static const char *wdays[] = { "Sun", "Mon", "Tue", "Wed", - "Thu", "Fri", "Sat"}; - strcpy(pre, wdays[ptime.wday]); - pre += 3; - } - if (log_decor & PJ_LOG_HAS_YEAR) { - *pre++ = ' '; - pre += pj_utoa(ptime.year, pre); - } - if (log_decor & PJ_LOG_HAS_MONTH) { - *pre++ = '-'; - pre += pj_utoa_pad(ptime.mon, pre, 2, '0'); - } - if (log_decor & PJ_LOG_HAS_DAY_OF_MON) { - *pre++ = ' '; - pre += pj_utoa_pad(ptime.day, pre, 2, '0'); - } - if (log_decor & PJ_LOG_HAS_TIME) { - *pre++ = ' '; - pre += pj_utoa_pad(ptime.hour, pre, 2, '0'); - *pre++ = ':'; - pre += pj_utoa_pad(ptime.min, pre, 2, '0'); - *pre++ = ':'; - pre += pj_utoa_pad(ptime.sec, pre, 2, '0'); - } - if (log_decor & PJ_LOG_HAS_MICRO_SEC) { - *pre++ = '.'; - pre += pj_utoa_pad(ptime.msec, pre, 3, '0'); - } - if (log_decor & PJ_LOG_HAS_SENDER) { - enum { SENDER_WIDTH = 12 }; - int sender_len = strlen(sender); - *pre++ = ' '; - if (sender_len <= SENDER_WIDTH) { - while (sender_len < SENDER_WIDTH) - *pre++ = ' ', ++sender_len; - while (*sender) - *pre++ = *sender++; - } else { - int i; - for (i=0; i 0 && len < sizeof(log_buffer)-1) { - if (log_decor & PJ_LOG_HAS_NEWLINE) { - log_buffer[len++] = '\n'; - } - log_buffer[len++] = '\0'; - } else { - len = sizeof(log_buffer)-1; - if (log_decor & PJ_LOG_HAS_NEWLINE) { - log_buffer[sizeof(log_buffer)-2] = '\n'; - } - log_buffer[sizeof(log_buffer)-1] = '\0'; - } - - if (log_writer) - (*log_writer)(level, log_buffer, len); -} - -PJ_DEF(void) pj_log_0(const char *obj, const char *format, ...) -{ - va_list arg; - va_start(arg, format); - pj_log(obj, 0, format, arg); - va_end(arg); -} - -PJ_DEF(void) pj_log_1(const char *obj, const char *format, ...) -{ - va_list arg; - va_start(arg, format); - pj_log(obj, 1, format, arg); - va_end(arg); -} -#endif /* PJ_LOG_MAX_LEVEL >= 1 */ - -#if PJ_LOG_MAX_LEVEL >= 2 -PJ_DEF(void) pj_log_2(const char *obj, const char *format, ...) -{ - va_list arg; - va_start(arg, format); - pj_log(obj, 2, format, arg); - va_end(arg); -} -#endif - -#if PJ_LOG_MAX_LEVEL >= 3 -PJ_DEF(void) pj_log_3(const char *obj, const char *format, ...) -{ - va_list arg; - va_start(arg, format); - pj_log(obj, 3, format, arg); - va_end(arg); -} -#endif - -#if PJ_LOG_MAX_LEVEL >= 4 -PJ_DEF(void) pj_log_4(const char *obj, const char *format, ...) -{ - va_list arg; - va_start(arg, format); - pj_log(obj, 4, format, arg); - va_end(arg); -} -#endif - -#if PJ_LOG_MAX_LEVEL >= 5 -PJ_DEF(void) pj_log_5(const char *obj, const char *format, ...) -{ - va_list arg; - va_start(arg, format); - pj_log(obj, 5, format, arg); - va_end(arg); -} -#endif - -#if PJ_LOG_MAX_LEVEL >= 6 -PJ_DEF(void) pj_log_6(const char *obj, const char *format, ...) -{ - va_list arg; - va_start(arg, format); - pj_log(obj, 6, format, arg); - va_end(arg); -} -#endif - +/* $Header: /pjproject-0.3/pjlib/src/pj/log.c 7 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/log.c $ + * + * 7 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 6 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include +#include +#include +#include +#include + +#if PJ_LOG_MAX_LEVEL >= 1 + +static int log_max_level = PJ_LOG_MAX_LEVEL; +static pj_log_func *log_writer = &pj_log_write; +static unsigned log_decor = PJ_LOG_HAS_TIME | PJ_LOG_HAS_MICRO_SEC | + PJ_LOG_HAS_SENDER | PJ_LOG_HAS_NEWLINE; + +#if PJ_LOG_USE_STACK_BUFFER==0 +static char log_buffer[PJ_LOG_MAX_SIZE]; +#endif + +PJ_DEF(void) pj_log_set_decor(unsigned decor) +{ + log_decor = decor; +} + +PJ_DEF(unsigned) pj_log_get_decor(void) +{ + return log_decor; +} + +PJ_DEF(void) pj_log_set_level(int level) +{ + log_max_level = level; +} + +PJ_DEF(int) pj_log_get_level(void) +{ + return log_max_level; +} + +PJ_DEF(void) pj_log_set_log_func( pj_log_func *func ) +{ + log_writer = func; +} + +PJ_DEF(pj_log_func*) pj_log_get_log_func(void) +{ + return log_writer; +} + +static void pj_log(const char *sender, int level, + const char *format, va_list marker) +{ + pj_time_val now; + pj_parsed_time ptime; + char *pre; +#if PJ_LOG_USE_STACK_BUFFER + char log_buffer[PJ_LOG_MAX_SIZE]; +#endif + int len; + + PJ_CHECK_STACK(); + + if (level > log_max_level) + return; + + /* Get current date/time. */ + pj_gettimeofday(&now); + pj_time_decode(&now, &ptime); + + pre = log_buffer; + if (log_decor & PJ_LOG_HAS_DAY_NAME) { + static const char *wdays[] = { "Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat"}; + strcpy(pre, wdays[ptime.wday]); + pre += 3; + } + if (log_decor & PJ_LOG_HAS_YEAR) { + *pre++ = ' '; + pre += pj_utoa(ptime.year, pre); + } + if (log_decor & PJ_LOG_HAS_MONTH) { + *pre++ = '-'; + pre += pj_utoa_pad(ptime.mon, pre, 2, '0'); + } + if (log_decor & PJ_LOG_HAS_DAY_OF_MON) { + *pre++ = ' '; + pre += pj_utoa_pad(ptime.day, pre, 2, '0'); + } + if (log_decor & PJ_LOG_HAS_TIME) { + *pre++ = ' '; + pre += pj_utoa_pad(ptime.hour, pre, 2, '0'); + *pre++ = ':'; + pre += pj_utoa_pad(ptime.min, pre, 2, '0'); + *pre++ = ':'; + pre += pj_utoa_pad(ptime.sec, pre, 2, '0'); + } + if (log_decor & PJ_LOG_HAS_MICRO_SEC) { + *pre++ = '.'; + pre += pj_utoa_pad(ptime.msec, pre, 3, '0'); + } + if (log_decor & PJ_LOG_HAS_SENDER) { + enum { SENDER_WIDTH = 12 }; + int sender_len = strlen(sender); + *pre++ = ' '; + if (sender_len <= SENDER_WIDTH) { + while (sender_len < SENDER_WIDTH) + *pre++ = ' ', ++sender_len; + while (*sender) + *pre++ = *sender++; + } else { + int i; + for (i=0; i 0 && len < sizeof(log_buffer)-1) { + if (log_decor & PJ_LOG_HAS_NEWLINE) { + log_buffer[len++] = '\n'; + } + log_buffer[len++] = '\0'; + } else { + len = sizeof(log_buffer)-1; + if (log_decor & PJ_LOG_HAS_NEWLINE) { + log_buffer[sizeof(log_buffer)-2] = '\n'; + } + log_buffer[sizeof(log_buffer)-1] = '\0'; + } + + if (log_writer) + (*log_writer)(level, log_buffer, len); +} + +PJ_DEF(void) pj_log_0(const char *obj, const char *format, ...) +{ + va_list arg; + va_start(arg, format); + pj_log(obj, 0, format, arg); + va_end(arg); +} + +PJ_DEF(void) pj_log_1(const char *obj, const char *format, ...) +{ + va_list arg; + va_start(arg, format); + pj_log(obj, 1, format, arg); + va_end(arg); +} +#endif /* PJ_LOG_MAX_LEVEL >= 1 */ + +#if PJ_LOG_MAX_LEVEL >= 2 +PJ_DEF(void) pj_log_2(const char *obj, const char *format, ...) +{ + va_list arg; + va_start(arg, format); + pj_log(obj, 2, format, arg); + va_end(arg); +} +#endif + +#if PJ_LOG_MAX_LEVEL >= 3 +PJ_DEF(void) pj_log_3(const char *obj, const char *format, ...) +{ + va_list arg; + va_start(arg, format); + pj_log(obj, 3, format, arg); + va_end(arg); +} +#endif + +#if PJ_LOG_MAX_LEVEL >= 4 +PJ_DEF(void) pj_log_4(const char *obj, const char *format, ...) +{ + va_list arg; + va_start(arg, format); + pj_log(obj, 4, format, arg); + va_end(arg); +} +#endif + +#if PJ_LOG_MAX_LEVEL >= 5 +PJ_DEF(void) pj_log_5(const char *obj, const char *format, ...) +{ + va_list arg; + va_start(arg, format); + pj_log(obj, 5, format, arg); + va_end(arg); +} +#endif + +#if PJ_LOG_MAX_LEVEL >= 6 +PJ_DEF(void) pj_log_6(const char *obj, const char *format, ...) +{ + va_list arg; + va_start(arg, format); + pj_log(obj, 6, format, arg); + va_end(arg); +} +#endif + diff --git a/pjlib/src/pj/log_writer_printk.c b/pjlib/src/pj/log_writer_printk.c index b18a3027..3f535c6b 100644 --- a/pjlib/src/pj/log_writer_printk.c +++ b/pjlib/src/pj/log_writer_printk.c @@ -1,20 +1,20 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/log_writer_printk.c 2 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/log_writer_printk.c $ - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 9/22/05 10:37a Bennylp - * Created. - * - */ -#include -#include - -PJ_DEF(void) pj_log_write(int level, const char *buffer, int len) -{ - PJ_CHECK_STACK(); - printk(KERN_INFO "%s", buffer); -} - +/* $Header: /pjproject-0.3/pjlib/src/pj/log_writer_printk.c 2 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/log_writer_printk.c $ + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 9/22/05 10:37a Bennylp + * Created. + * + */ +#include +#include + +PJ_DEF(void) pj_log_write(int level, const char *buffer, int len) +{ + PJ_CHECK_STACK(); + printk(KERN_INFO "%s", buffer); +} + diff --git a/pjlib/src/pj/log_writer_stdout.c b/pjlib/src/pj/log_writer_stdout.c index 30a7a6f1..abaeb6d0 100644 --- a/pjlib/src/pj/log_writer_stdout.c +++ b/pjlib/src/pj/log_writer_stdout.c @@ -1,66 +1,66 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/log_writer_stdout.c 5 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/log_writer_stdout.c $ - * - * 5 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 4 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 3 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include - -#define CLR_FATAL (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R) -#define CLR_WARNING (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R | PJ_TERM_COLOR_G) -#define CLR_INFO (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R | PJ_TERM_COLOR_G | \ - PJ_TERM_COLOR_B) -#define CLR_DEFAULT (PJ_TERM_COLOR_R | PJ_TERM_COLOR_G | PJ_TERM_COLOR_B) - -static void term_set_color(int level) -{ -#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0 - unsigned attr = 0; - switch (level) { - case 0: - case 1: attr = CLR_FATAL; - break; - case 2: attr = CLR_WARNING; - break; - case 3: attr = CLR_INFO; - break; - default: - attr = CLR_DEFAULT; - break; - } - - pj_term_set_color(attr); -#endif -} - -static void term_restore_color(void) -{ -#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0 - pj_term_set_color(CLR_DEFAULT); -#endif -} - - -PJ_DEF(void) pj_log_write(int level, const char *buffer, int len) -{ - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(len); - - /* Copy to terminal/file. */ - term_set_color(level); - fputs(buffer, stdout); - term_restore_color(); - - fflush(stdout); -} - +/* $Header: /pjproject-0.3/pjlib/src/pj/log_writer_stdout.c 5 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/log_writer_stdout.c $ + * + * 5 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 4 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 3 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include +#include + +#define CLR_FATAL (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R) +#define CLR_WARNING (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R | PJ_TERM_COLOR_G) +#define CLR_INFO (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R | PJ_TERM_COLOR_G | \ + PJ_TERM_COLOR_B) +#define CLR_DEFAULT (PJ_TERM_COLOR_R | PJ_TERM_COLOR_G | PJ_TERM_COLOR_B) + +static void term_set_color(int level) +{ +#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0 + unsigned attr = 0; + switch (level) { + case 0: + case 1: attr = CLR_FATAL; + break; + case 2: attr = CLR_WARNING; + break; + case 3: attr = CLR_INFO; + break; + default: + attr = CLR_DEFAULT; + break; + } + + pj_term_set_color(attr); +#endif +} + +static void term_restore_color(void) +{ +#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0 + pj_term_set_color(CLR_DEFAULT); +#endif +} + + +PJ_DEF(void) pj_log_write(int level, const char *buffer, int len) +{ + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(len); + + /* Copy to terminal/file. */ + term_set_color(level); + fputs(buffer, stdout); + term_restore_color(); + + fflush(stdout); +} + diff --git a/pjlib/src/pj/md5.c b/pjlib/src/pj/md5.c index 3c42b4ed..c796ce8c 100644 --- a/pjlib/src/pj/md5.c +++ b/pjlib/src/pj/md5.c @@ -1,404 +1,404 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/md5.c 5 10/14/05 12:26a Bennylp $ */ -/* - Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.c is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order - either statically or dynamically; added missing #include - in library. - 2002-03-11 lpd Corrected argument list for main(), and added int return - type, in test program and T value program. - 2002-02-21 lpd Added missing #include in test program. - 2000-07-03 lpd Patched to eliminate warnings about "constant is - unsigned in ANSI C, signed in traditional"; made test program - self-checking. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). - 1999-05-03 lpd Original version. - */ - -#include -#include -#include - -#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ - -/* -#ifdef ARCH_IS_BIG_ENDIAN -# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) -#else -# define BYTE_ORDER 0 -#endif -*/ -/* pjlib: */ -#include -#if PJ_IS_LITTLE_ENDIAN -# define BYTE_ORDER -1 -#elif PJ_IS_BIG_ENDIAN -# define BYTE_ORDER 1 -#else -# error Endianess is not known! -#endif - - -#define T_MASK ((md5_word_t)~0) -#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) -#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) -#define T3 0x242070db -#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) -#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) -#define T6 0x4787c62a -#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) -#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) -#define T9 0x698098d8 -#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) -#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) -#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) -#define T13 0x6b901122 -#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) -#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) -#define T16 0x49b40821 -#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) -#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) -#define T19 0x265e5a51 -#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) -#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) -#define T22 0x02441453 -#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) -#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) -#define T25 0x21e1cde6 -#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) -#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) -#define T28 0x455a14ed -#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) -#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) -#define T31 0x676f02d9 -#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) -#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) -#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) -#define T35 0x6d9d6122 -#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) -#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) -#define T38 0x4bdecfa9 -#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) -#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) -#define T41 0x289b7ec6 -#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) -#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) -#define T44 0x04881d05 -#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) -#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) -#define T47 0x1fa27cf8 -#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) -#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) -#define T50 0x432aff97 -#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) -#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) -#define T53 0x655b59c3 -#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) -#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) -#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) -#define T57 0x6fa87e4f -#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) -#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) -#define T60 0x4e0811a1 -#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) -#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) -#define T63 0x2ad7d2bb -#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) - - -static void -md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) -{ - md5_word_t - a = pms->abcd[0], b = pms->abcd[1], - c = pms->abcd[2], d = pms->abcd[3]; - md5_word_t t; -#if BYTE_ORDER > 0 - /* Define storage only for big-endian CPUs. */ - md5_word_t X[16]; -#else - /* Define storage for little-endian or both types of CPUs. */ - md5_word_t xbuf[16]; - const md5_word_t *X; -#endif - - PJ_CHECK_STACK(); - - { -#if BYTE_ORDER == 0 - /* - * Determine dynamically whether this is a big-endian or - * little-endian machine, since we can use a more efficient - * algorithm on the latter. - */ - static const int w = 1; - - if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ -#endif -#if BYTE_ORDER <= 0 /* little-endian */ - { - /* - * On little-endian machines, we can process properly aligned - * data without copying it. - */ - if (!((data - (const md5_byte_t *)0) & 3)) { - /* data are properly aligned */ - X = (const md5_word_t *)data; - } else { - /* not aligned */ - memcpy(xbuf, data, 64); - X = xbuf; - } - } -#endif -#if BYTE_ORDER == 0 - else /* dynamic big-endian */ -#endif -#if BYTE_ORDER >= 0 /* big-endian */ - { - /* - * On big-endian machines, we must arrange the bytes in the - * right order. - */ - const md5_byte_t *xp = data; - int i; - -# if BYTE_ORDER == 0 - X = xbuf; /* (dynamic only) */ -# else -# define xbuf X /* (static only) */ -# endif - for (i = 0; i < 16; ++i, xp += 4) - xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); - } -#endif - } - -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - - /* Round 1. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + F(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 7, T1); - SET(d, a, b, c, 1, 12, T2); - SET(c, d, a, b, 2, 17, T3); - SET(b, c, d, a, 3, 22, T4); - SET(a, b, c, d, 4, 7, T5); - SET(d, a, b, c, 5, 12, T6); - SET(c, d, a, b, 6, 17, T7); - SET(b, c, d, a, 7, 22, T8); - SET(a, b, c, d, 8, 7, T9); - SET(d, a, b, c, 9, 12, T10); - SET(c, d, a, b, 10, 17, T11); - SET(b, c, d, a, 11, 22, T12); - SET(a, b, c, d, 12, 7, T13); - SET(d, a, b, c, 13, 12, T14); - SET(c, d, a, b, 14, 17, T15); - SET(b, c, d, a, 15, 22, T16); -#undef SET - - /* Round 2. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + G(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 1, 5, T17); - SET(d, a, b, c, 6, 9, T18); - SET(c, d, a, b, 11, 14, T19); - SET(b, c, d, a, 0, 20, T20); - SET(a, b, c, d, 5, 5, T21); - SET(d, a, b, c, 10, 9, T22); - SET(c, d, a, b, 15, 14, T23); - SET(b, c, d, a, 4, 20, T24); - SET(a, b, c, d, 9, 5, T25); - SET(d, a, b, c, 14, 9, T26); - SET(c, d, a, b, 3, 14, T27); - SET(b, c, d, a, 8, 20, T28); - SET(a, b, c, d, 13, 5, T29); - SET(d, a, b, c, 2, 9, T30); - SET(c, d, a, b, 7, 14, T31); - SET(b, c, d, a, 12, 20, T32); -#undef SET - - /* Round 3. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + H(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 5, 4, T33); - SET(d, a, b, c, 8, 11, T34); - SET(c, d, a, b, 11, 16, T35); - SET(b, c, d, a, 14, 23, T36); - SET(a, b, c, d, 1, 4, T37); - SET(d, a, b, c, 4, 11, T38); - SET(c, d, a, b, 7, 16, T39); - SET(b, c, d, a, 10, 23, T40); - SET(a, b, c, d, 13, 4, T41); - SET(d, a, b, c, 0, 11, T42); - SET(c, d, a, b, 3, 16, T43); - SET(b, c, d, a, 6, 23, T44); - SET(a, b, c, d, 9, 4, T45); - SET(d, a, b, c, 12, 11, T46); - SET(c, d, a, b, 15, 16, T47); - SET(b, c, d, a, 2, 23, T48); -#undef SET - - /* Round 4. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + I(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 6, T49); - SET(d, a, b, c, 7, 10, T50); - SET(c, d, a, b, 14, 15, T51); - SET(b, c, d, a, 5, 21, T52); - SET(a, b, c, d, 12, 6, T53); - SET(d, a, b, c, 3, 10, T54); - SET(c, d, a, b, 10, 15, T55); - SET(b, c, d, a, 1, 21, T56); - SET(a, b, c, d, 8, 6, T57); - SET(d, a, b, c, 15, 10, T58); - SET(c, d, a, b, 6, 15, T59); - SET(b, c, d, a, 13, 21, T60); - SET(a, b, c, d, 4, 6, T61); - SET(d, a, b, c, 11, 10, T62); - SET(c, d, a, b, 2, 15, T63); - SET(b, c, d, a, 9, 21, T64); -#undef SET - - /* Then perform the following additions. (That is increment each - of the four registers by the value it had before this block - was started.) */ - pms->abcd[0] += a; - pms->abcd[1] += b; - pms->abcd[2] += c; - pms->abcd[3] += d; -} - -void -md5_init(md5_state_t *pms) -{ - PJ_CHECK_STACK(); - - pms->count[0] = pms->count[1] = 0; - pms->abcd[0] = 0x67452301; - pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; - pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; - pms->abcd[3] = 0x10325476; -} - -void -md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) -{ - const md5_byte_t *p = data; - int left = nbytes; - int offset = (pms->count[0] >> 3) & 63; - md5_word_t nbits = (md5_word_t)(nbytes << 3); - - PJ_CHECK_STACK(); - - if (nbytes <= 0) - return; - - /* Update the message length. */ - pms->count[1] += nbytes >> 29; - pms->count[0] += nbits; - if (pms->count[0] < nbits) - pms->count[1]++; - - /* Process an initial partial block. */ - if (offset) { - int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - - memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - md5_process(pms, pms->buf); - } - - /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); - - /* Process a final partial block. */ - if (left) - memcpy(pms->buf, p, left); -} - -void -md5_finish(md5_state_t *pms, md5_byte_t digest[16]) -{ - static const md5_byte_t pad[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - md5_byte_t data[8]; - int i; - - PJ_CHECK_STACK(); - - /* Save the length before padding. */ - for (i = 0; i < 8; ++i) - data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); - /* Pad to 56 bytes mod 64. */ - md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); - /* Append the length. */ - md5_append(pms, data, 8); - for (i = 0; i < 16; ++i) - digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); -} +/* $Header: /pjproject-0.3/pjlib/src/pj/md5.c 5 10/14/05 12:26a Bennylp $ */ +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include +#include +#include + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ + +/* +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif +*/ +/* pjlib: */ +#include +#if PJ_IS_LITTLE_ENDIAN +# define BYTE_ORDER -1 +#elif PJ_IS_BIG_ENDIAN +# define BYTE_ORDER 1 +#else +# error Endianess is not known! +#endif + + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; +#endif + + PJ_CHECK_STACK(); + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + +# if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + PJ_CHECK_STACK(); + + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + PJ_CHECK_STACK(); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + PJ_CHECK_STACK(); + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/pjlib/src/pj/os_core_linux_kernel.c b/pjlib/src/pj/os_core_linux_kernel.c index 82edccb4..f843e637 100644 --- a/pjlib/src/pj/os_core_linux_kernel.c +++ b/pjlib/src/pj/os_core_linux_kernel.c @@ -1,685 +1,686 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/os_core_linux_kernel.c 3 10/29/05 11:51a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/os_core_linux_kernel.c $ - * - * 3 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 9/22/05 10:38a Bennylp - * Creaetd. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#if defined(MODVERSIONS) -#include -#endif -#include -#include -//#include -#include -#include - -#include -#include -#include - -#define THIS_FILE "oslinuxkern" - -struct pj_thread_t -{ - /** Thread's name. */ - char obj_name[PJ_MAX_OBJ_NAME]; - - /** Linux task structure for thread. */ - struct task_struct *thread; - - /** Flags (specified in pj_thread_create) */ - unsigned flags; - - /** Task queue needed to launch thread. */ - //struct tq_struct tq; - - /** Semaphore needed to control thread startup. */ - struct semaphore startstop_sem; - - /** Semaphore to suspend thread during startup. */ - struct semaphore suspend_sem; - - /** Queue thread is waiting on. Gets initialized by - thread_initialize, can be used by thread itself. - */ - wait_queue_head_t queue; - - /** Flag to tell thread whether to die or not. - When the thread receives a signal, it must check - the value of terminate and call thread_deinitialize and terminate - if set. - */ - int terminate; - - /** Thread's entry. */ - pj_thread_proc *func; - - /** Argument. */ - void *arg; -}; - -struct pj_atomic_t -{ - atomic_t atom; -}; - -struct pj_mutex_t -{ - struct semaphore sem; - pj_bool_t recursive; - pj_thread_t *owner; - int own_count; -}; - -struct pj_sem_t -{ - struct semaphore sem; -}; - -/* - * Static global variables. - */ -#define MAX_TLS_ID 32 -static void *tls_values[MAX_TLS_ID]; -static int tls_id; -static long thread_tls_id; -static spinlock_t critical_section = SPIN_LOCK_UNLOCKED; -static unsigned long spinlock_flags; -static pj_thread_t main_thread; - -/* private functions */ -//#define TRACE_(expr) PJ_LOG(3,expr) -#define TRACE_(x) - - -/* This must be called in the context of the new thread. */ -static void thread_initialize( pj_thread_t *thread ) -{ - TRACE_((THIS_FILE, "---new thread initializing...")); - - /* Set TLS */ - pj_thread_local_set(thread_tls_id, thread); - - /* fill in thread structure */ - thread->thread = current; - pj_assert(thread->thread != NULL); - - /* set signal mask to what we want to respond */ - siginitsetinv(¤t->blocked, - sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM)); - - /* initialise wait queue */ - init_waitqueue_head(&thread->queue); - - /* initialise termination flag */ - thread->terminate = 0; - - /* set name of this process (max 15 chars + 0 !) */ - thread->obj_name[15] = '\0'; - sprintf(current->comm, thread->obj_name); - - /* tell the creator that we are ready and let him continue */ - up(&thread->startstop_sem); -} - -/* cleanup of thread. Called by the exiting thread. */ -static void thread_deinitialize(pj_thread_t *thread) -{ - /* we are terminating */ - - /* lock the kernel, the exit will unlock it */ - thread->thread = NULL; - mb(); - - /* notify the stop_kthread() routine that we are terminating. */ - up(&thread->startstop_sem); - - /* the kernel_thread that called clone() does a do_exit here. */ - - /* there is no race here between execution of the "killer" and - real termination of the thread (race window between up and do_exit), - since both the thread and the "killer" function are running with - the kernel lock held. - The kernel lock will be freed after the thread exited, so the code - is really not executed anymore as soon as the unload functions gets - the kernel lock back. - The init process may not have made the cleanup of the process here, - but the cleanup can be done safely with the module unloaded. - */ - -} - -static int thread_proc(void *arg) -{ - pj_thread_t *thread = arg; - - TRACE_((THIS_FILE, "---new thread starting!")); - - /* Initialize thread. */ - thread_initialize( thread ); - - /* Wait if created suspended. */ - if (thread->flags & PJ_THREAD_SUSPENDED) { - TRACE_((THIS_FILE, "---new thread suspended...")); - down(&thread->suspend_sem); - } - - TRACE_((THIS_FILE, "---new thread running...")); - - pj_assert(thread->func != NULL); - - /* Call thread's entry. */ - (*thread->func)(thread->arg); - - TRACE_((THIS_FILE, "---thread exiting...")); - - /* Cleanup thread. */ - thread_deinitialize(thread); - - return 0; -} - -/* The very task entry. */ -static void kthread_launcher(void *arg) -{ - TRACE_((THIS_FILE, "...launching thread!...")); - kernel_thread(&thread_proc, arg, 0); -} - -PJ_DEF(pj_status_t) pj_init(void) -{ - pj_status_t rc; - - PJ_LOG(5, ("pj_init", "Initializing PJ Library..")); - - rc = pj_thread_init(); - if (rc != PJ_SUCCESS) - return rc; - - /* Initialize exception ID for the pool. - * Must do so after critical section is configured. - */ - rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION); - if (rc != PJ_SUCCESS) - return rc; - - return PJ_SUCCESS; -} - -PJ_DEF(pj_uint32_t) pj_getpid(void) -{ - return 1; -} - -PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name, - pj_thread_desc desc, - pj_thread_t **ptr_thread) -{ - char stack_ptr; - pj_thread_t *thread = (pj_thread_t *)desc; - pj_str_t thread_name = pj_str((char*)cstr_thread_name); - - /* Size sanity check. */ - if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) { - pj_assert(!"Not enough pj_thread_desc size!"); - return PJ_EBUG; - } - - /* If a thread descriptor has been registered before, just return it. */ - if (pj_thread_local_get (thread_tls_id) != 0) { - *ptr_thread = (pj_thread_t*)pj_thread_local_get (thread_tls_id); - return PJ_SUCCESS; - } - - /* Initialize and set the thread entry. */ - pj_memset(desc, 0, sizeof(pj_thread_desc)); - - if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1) - pj_sprintf(thread->obj_name, cstr_thread_name, thread->thread); - else - pj_sprintf(thread->obj_name, "thr%p", (void*)thread->thread); - - /* Initialize. */ - thread_initialize(thread); - - /* Eat semaphore. */ - down(&thread->startstop_sem); - -#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 - thread->stk_start = &stack_ptr; - thread->stk_size = 0xFFFFFFFFUL; - thread->stk_max_usage = 0; -#else - stack_ptr = '\0'; -#endif - - *ptr_thread = thread; - return PJ_SUCCESS; -} - - -pj_status_t pj_thread_init(void) -{ - pj_status_t rc; - pj_thread_t *dummy; - - rc = pj_thread_local_alloc(&thread_tls_id); - if (rc != PJ_SUCCESS) - return rc; - - return pj_thread_register("pjlib-main", (pj_uint8_t*)&main_thread, &dummy); -} - -PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, const char *thread_name, - pj_thread_proc *proc, void *arg, - pj_size_t stack_size, unsigned flags, - pj_thread_t **ptr_thread) -{ - pj_thread_t *thread; - - TRACE_((THIS_FILE, "pj_thread_create()")); - - PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL); - - thread = pj_pool_zalloc(pool, sizeof(pj_thread_t)); - if (!thread) - return PJ_ENOMEM; - - PJ_UNUSED_ARG(stack_size); - - /* Thread name. */ - if (!thread_name) - thread_name = "thr%p"; - - if (strchr(thread_name, '%')) { - pj_snprintf(thread->obj_name, PJ_MAX_OBJ_NAME, thread_name, thread); - } else { - strncpy(thread->obj_name, thread_name, PJ_MAX_OBJ_NAME); - thread->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; - } - - /* Init thread's semaphore. */ - TRACE_((THIS_FILE, "...init semaphores...")); - init_MUTEX_LOCKED(&thread->startstop_sem); - init_MUTEX_LOCKED(&thread->suspend_sem); - - thread->flags = flags; - - if ((flags & PJ_THREAD_SUSPENDED) == 0) { - up(&thread->suspend_sem); - } - - /* Store the functions and argument. */ - thread->func = proc; - thread->arg = arg; - - /* Save return value. */ - *ptr_thread = thread; - - /* Create the new thread by running a task through keventd. */ - -#if 0 - /* Initialize the task queue struct. */ - thread->tq.sync = 0; - INIT_LIST_HEAD(&thread->tq.list); - thread->tq.routine = kthread_launcher; - thread->tq.data = thread; - - /* and schedule it for execution. */ - schedule_task(&thread->tq); -#endif - kthread_launcher(thread); - - /* Wait until thread has reached the setup_thread routine. */ - TRACE_((THIS_FILE, "...wait for the new thread...")); - down(&thread->startstop_sem); - - TRACE_((THIS_FILE, "...main thread resumed...")); - return PJ_SUCCESS; -} - -PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *thread) -{ - return thread->obj_name; -} - -PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *thread) -{ - up(&thread->suspend_sem); - return PJ_SUCCESS; -} - -PJ_DEF(pj_thread_t*) pj_thread_this(void) -{ - return (pj_thread_t*)pj_thread_local_get(thread_tls_id); -} - -PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p) -{ - TRACE_((THIS_FILE, "pj_thread_join()")); - down(&p->startstop_sem); - TRACE_((THIS_FILE, " joined!")); - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *thread) -{ - PJ_ASSERT_RETURN(thread != NULL, PJ_EINVALIDOP); - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec) -{ - pj_highprec_t ticks; - pj_thread_t *thread = pj_thread_this(); - - PJ_ASSERT_RETURN(thread != NULL, PJ_EBUG); - - /* Use high precision calculation to make sure we don't - * crop values: - * - * ticks = HZ * msec / 1000 - */ - ticks = HZ; - pj_highprec_mul(ticks, msec); - pj_highprec_div(ticks, 1000); - - TRACE_((THIS_FILE, "this thread will sleep for %u ticks", ticks)); - interruptible_sleep_on_timeout( &thread->queue, ticks); - return PJ_SUCCESS; -} - - -/////////////////////////////////////////////////////////////////////////////// -PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, - pj_atomic_value_t value, - pj_atomic_t **ptr_var) -{ - pj_atomic_t *t = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t)); - if (!t) return PJ_ENOMEM; - - atomic_set(&t->atom, value); - *ptr_var = t; - - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var ) -{ - return 0; -} - -PJ_DEF(pj_atomic_value_t) pj_atomic_set(pj_atomic_t *var, - pj_atomic_value_t value) -{ - pj_atomic_value_t oldval = atomic_read(&var->atom); - atomic_set(&var->atom, value); - return oldval; -} - -PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *var) -{ - return atomic_read(&var->atom); -} - -PJ_DEF(pj_atomic_value_t) pj_atomic_inc(pj_atomic_t *var) -{ - atomic_inc(&var->atom); - return atomic_read(&var->atom); -} - -PJ_DEF(pj_atomic_value_t) pj_atomic_dec(pj_atomic_t *var) -{ - atomic_dec(&var->atom); - return atomic_read(&var->atom); -} - - - -/////////////////////////////////////////////////////////////////////////////// -PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index) -{ - if (tls_id >= MAX_TLS_ID) - return PJ_ETOOMANY; - - *index = tls_id++; - - return PJ_SUCCESS; -} - -PJ_DEF(void) pj_thread_local_free(long index) -{ - pj_assert(index >= 0 && index < MAX_TLS_ID); -} - -PJ_DEF(void) pj_thread_local_set(long index, void *value) -{ - pj_assert(index >= 0 && index < MAX_TLS_ID); - tls_values[index] = value; -} - -PJ_DEF(void*) pj_thread_local_get(long index) -{ - pj_assert(index >= 0 && index < MAX_TLS_ID); - return tls_values[index]; -} - - -/////////////////////////////////////////////////////////////////////////////// -PJ_DEF(void) pj_enter_critical_section(void) -{ - spin_lock_irqsave(&critical_section, spinlock_flags); -} - -PJ_DEF(void) pj_leave_critical_section(void) -{ - spin_unlock_irqrestore(&critical_section, spinlock_flags); -} - - -/////////////////////////////////////////////////////////////////////////////// -PJ_DEF(pj_status_t) pj_mutex_create( pj_pool_t *pool, - const char *name, - int type, - pj_mutex_t **ptr_mutex) -{ - pj_mutex_t *mutex; - - PJ_UNUSED_ARG(name); - - mutex = pj_pool_alloc(pool, sizeof(pj_mutex_t)); - if (!mutex) - return PJ_ENOMEM; - - init_MUTEX(&mutex->sem); - - mutex->recursive = (type == PJ_MUTEX_RECURSE); - mutex->owner = NULL; - mutex->own_count = 0; - - /* Done. */ - *ptr_mutex = mutex; - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name, - pj_mutex_t **mutex ) -{ - return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex); -} - -PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool, - const char *name, - pj_mutex_t **mutex ) -{ - return pj_mutex_create( pool, name, PJ_MUTEX_RECURSE, mutex); -} - -PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex) -{ - PJ_ASSERT_RETURN(mutex, PJ_EINVAL); - - if (mutex->recursive) { - pj_thread_t *this_thread = pj_thread_this(); - if (mutex->owner == this_thread) { - ++mutex->own_count; - } else { - down(&mutex->sem); - pj_assert(mutex->own_count == 0); - mutex->owner = this_thread; - mutex->own_count = 1; - } - } else { - down(&mutex->sem); - } - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex) -{ - long rc; - - PJ_ASSERT_RETURN(mutex, PJ_EINVAL); - - if (mutex->recursive) { - pj_thread_t *this_thread = pj_thread_this(); - if (mutex->owner == this_thread) { - ++mutex->own_count; - } else { - rc = down_interruptible(&mutex->sem); - if (rc != 0) - return PJ_RETURN_OS_ERROR(-rc); - pj_assert(mutex->own_count == 0); - mutex->owner = this_thread; - mutex->own_count = 1; - } - } else { - int rc = down_trylock(&mutex->sem); - if (rc != 0) - return PJ_RETURN_OS_ERROR(-rc); - } - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex) -{ - PJ_ASSERT_RETURN(mutex, PJ_EINVAL); - - if (mutex->recursive) { - pj_thread_t *this_thread = pj_thread_this(); - if (mutex->owner == this_thread) { - pj_assert(mutex->own_count > 0); - --mutex->own_count; - if (mutex->own_count == 0) { - mutex->owner = NULL; - up(&mutex->sem); - } - } else { - pj_assert(!"Not owner!"); - return PJ_EINVALIDOP; - } - } else { - up(&mutex->sem); - } - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex) -{ - PJ_ASSERT_RETURN(mutex != NULL, PJ_EINVAL); - - return PJ_SUCCESS; -} - -#if defined(PJ_DEBUG) && PJ_DEBUG != 0 -PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex) -{ - if (mutex->recursive) - return mutex->owner == pj_thread_this(); - else - return 1; -} -#endif /* PJ_DEBUG */ - - -#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 - -PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool, - const char *name, - unsigned initial, - unsigned max, - pj_sem_t **sem) -{ - pj_sem_t *sem; - - PJ_UNUSED_ARG(max); - - PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL); - - sem = pj_pool_alloc(pool, sizeof(pj_sem_t)); - sema_init(&sem->sem, initial); - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem) -{ - PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL); - - down(&sem->sem); - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem) -{ - int rc; - - PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL); - - rc = down_trylock(&sem->sem); - if (rc != 0) { - return PJ_RETURN_OS_ERROR(-rc); - } else { - return PJ_SUCCESS; - } -} - -PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem) -{ - PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL); - - up(&sem->sem); - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem) -{ - PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL); - - return PJ_SUCCESS; -} - -#endif /* PJ_HAS_SEMAPHORE */ - - - - +/* $Header: /pjproject-0.3/pjlib/src/pj/os_core_linux_kernel.c 3 10/29/05 11:51a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/os_core_linux_kernel.c $ + * + * 3 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 9/22/05 10:38a Bennylp + * Creaetd. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#if defined(MODVERSIONS) +#include +#endif +#include +#include +//#include +#include +#include + +#include +#include +#include + +#define THIS_FILE "oslinuxkern" + +struct pj_thread_t +{ + /** Thread's name. */ + char obj_name[PJ_MAX_OBJ_NAME]; + + /** Linux task structure for thread. */ + struct task_struct *thread; + + /** Flags (specified in pj_thread_create) */ + unsigned flags; + + /** Task queue needed to launch thread. */ + //struct tq_struct tq; + + /** Semaphore needed to control thread startup. */ + struct semaphore startstop_sem; + + /** Semaphore to suspend thread during startup. */ + struct semaphore suspend_sem; + + /** Queue thread is waiting on. Gets initialized by + thread_initialize, can be used by thread itself. + */ + wait_queue_head_t queue; + + /** Flag to tell thread whether to die or not. + When the thread receives a signal, it must check + the value of terminate and call thread_deinitialize and terminate + if set. + */ + int terminate; + + /** Thread's entry. */ + pj_thread_proc *func; + + /** Argument. */ + void *arg; +}; + +struct pj_atomic_t +{ + atomic_t atom; +}; + +struct pj_mutex_t +{ + struct semaphore sem; + pj_bool_t recursive; + pj_thread_t *owner; + int own_count; +}; + +struct pj_sem_t +{ + struct semaphore sem; +}; + +/* + * Static global variables. + */ +#define MAX_TLS_ID 32 +static void *tls_values[MAX_TLS_ID]; +static int tls_id; +static long thread_tls_id; +static spinlock_t critical_section = SPIN_LOCK_UNLOCKED; +static unsigned long spinlock_flags; +static pj_thread_t main_thread; + +/* private functions */ +//#define TRACE_(expr) PJ_LOG(3,expr) +#define TRACE_(x) + + +/* This must be called in the context of the new thread. */ +static void thread_initialize( pj_thread_t *thread ) +{ + TRACE_((THIS_FILE, "---new thread initializing...")); + + /* Set TLS */ + pj_thread_local_set(thread_tls_id, thread); + + /* fill in thread structure */ + thread->thread = current; + pj_assert(thread->thread != NULL); + + /* set signal mask to what we want to respond */ + siginitsetinv(¤t->blocked, + sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM)); + + /* initialise wait queue */ + init_waitqueue_head(&thread->queue); + + /* initialise termination flag */ + thread->terminate = 0; + + /* set name of this process (max 15 chars + 0 !) */ + thread->obj_name[15] = '\0'; + sprintf(current->comm, thread->obj_name); + + /* tell the creator that we are ready and let him continue */ + up(&thread->startstop_sem); +} + +/* cleanup of thread. Called by the exiting thread. */ +static void thread_deinitialize(pj_thread_t *thread) +{ + /* we are terminating */ + + /* lock the kernel, the exit will unlock it */ + thread->thread = NULL; + mb(); + + /* notify the stop_kthread() routine that we are terminating. */ + up(&thread->startstop_sem); + + /* the kernel_thread that called clone() does a do_exit here. */ + + /* there is no race here between execution of the "killer" and + real termination of the thread (race window between up and do_exit), + since both the thread and the "killer" function are running with + the kernel lock held. + The kernel lock will be freed after the thread exited, so the code + is really not executed anymore as soon as the unload functions gets + the kernel lock back. + The init process may not have made the cleanup of the process here, + but the cleanup can be done safely with the module unloaded. + */ + +} + +static int thread_proc(void *arg) +{ + pj_thread_t *thread = arg; + + TRACE_((THIS_FILE, "---new thread starting!")); + + /* Initialize thread. */ + thread_initialize( thread ); + + /* Wait if created suspended. */ + if (thread->flags & PJ_THREAD_SUSPENDED) { + TRACE_((THIS_FILE, "---new thread suspended...")); + down(&thread->suspend_sem); + } + + TRACE_((THIS_FILE, "---new thread running...")); + + pj_assert(thread->func != NULL); + + /* Call thread's entry. */ + (*thread->func)(thread->arg); + + TRACE_((THIS_FILE, "---thread exiting...")); + + /* Cleanup thread. */ + thread_deinitialize(thread); + + return 0; +} + +/* The very task entry. */ +static void kthread_launcher(void *arg) +{ + TRACE_((THIS_FILE, "...launching thread!...")); + kernel_thread(&thread_proc, arg, 0); +} + +PJ_DEF(pj_status_t) pj_init(void) +{ + pj_status_t rc; + + PJ_LOG(5, ("pj_init", "Initializing PJ Library..")); + + rc = pj_thread_init(); + if (rc != PJ_SUCCESS) + return rc; + + /* Initialize exception ID for the pool. + * Must do so after critical section is configured. + */ + rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION); + if (rc != PJ_SUCCESS) + return rc; + + return PJ_SUCCESS; +} + +PJ_DEF(pj_uint32_t) pj_getpid(void) +{ + return 1; +} + +PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name, + pj_thread_desc desc, + pj_thread_t **ptr_thread) +{ + char stack_ptr; + pj_thread_t *thread = (pj_thread_t *)desc; + pj_str_t thread_name = pj_str((char*)cstr_thread_name); + + /* Size sanity check. */ + if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) { + pj_assert(!"Not enough pj_thread_desc size!"); + return PJ_EBUG; + } + + /* If a thread descriptor has been registered before, just return it. */ + if (pj_thread_local_get (thread_tls_id) != 0) { + *ptr_thread = (pj_thread_t*)pj_thread_local_get (thread_tls_id); + return PJ_SUCCESS; + } + + /* Initialize and set the thread entry. */ + pj_memset(desc, 0, sizeof(struct pj_thread_t)); + + if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1) + pj_sprintf(thread->obj_name, cstr_thread_name, thread->thread); + else + pj_sprintf(thread->obj_name, "thr%p", (void*)thread->thread); + + /* Initialize. */ + thread_initialize(thread); + + /* Eat semaphore. */ + down(&thread->startstop_sem); + +#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 + thread->stk_start = &stack_ptr; + thread->stk_size = 0xFFFFFFFFUL; + thread->stk_max_usage = 0; +#else + stack_ptr = '\0'; +#endif + + *ptr_thread = thread; + return PJ_SUCCESS; +} + + +pj_status_t pj_thread_init(void) +{ + pj_status_t rc; + pj_thread_t *dummy; + + rc = pj_thread_local_alloc(&thread_tls_id); + if (rc != PJ_SUCCESS) + return rc; + + return pj_thread_register("pjlib-main", (long*)&main_thread, &dummy); +} + +PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, const char *thread_name, + pj_thread_proc *proc, void *arg, + pj_size_t stack_size, unsigned flags, + pj_thread_t **ptr_thread) +{ + pj_thread_t *thread; + + TRACE_((THIS_FILE, "pj_thread_create()")); + + PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL); + + thread = pj_pool_zalloc(pool, sizeof(pj_thread_t)); + if (!thread) + return PJ_ENOMEM; + + PJ_UNUSED_ARG(stack_size); + + /* Thread name. */ + if (!thread_name) + thread_name = "thr%p"; + + if (strchr(thread_name, '%')) { + pj_snprintf(thread->obj_name, PJ_MAX_OBJ_NAME, thread_name, thread); + } else { + strncpy(thread->obj_name, thread_name, PJ_MAX_OBJ_NAME); + thread->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; + } + + /* Init thread's semaphore. */ + TRACE_((THIS_FILE, "...init semaphores...")); + init_MUTEX_LOCKED(&thread->startstop_sem); + init_MUTEX_LOCKED(&thread->suspend_sem); + + thread->flags = flags; + + if ((flags & PJ_THREAD_SUSPENDED) == 0) { + up(&thread->suspend_sem); + } + + /* Store the functions and argument. */ + thread->func = proc; + thread->arg = arg; + + /* Save return value. */ + *ptr_thread = thread; + + /* Create the new thread by running a task through keventd. */ + +#if 0 + /* Initialize the task queue struct. */ + thread->tq.sync = 0; + INIT_LIST_HEAD(&thread->tq.list); + thread->tq.routine = kthread_launcher; + thread->tq.data = thread; + + /* and schedule it for execution. */ + schedule_task(&thread->tq); +#endif + kthread_launcher(thread); + + /* Wait until thread has reached the setup_thread routine. */ + TRACE_((THIS_FILE, "...wait for the new thread...")); + down(&thread->startstop_sem); + + TRACE_((THIS_FILE, "...main thread resumed...")); + return PJ_SUCCESS; +} + +PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *thread) +{ + return thread->obj_name; +} + +PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *thread) +{ + up(&thread->suspend_sem); + return PJ_SUCCESS; +} + +PJ_DEF(pj_thread_t*) pj_thread_this(void) +{ + return (pj_thread_t*)pj_thread_local_get(thread_tls_id); +} + +PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p) +{ + TRACE_((THIS_FILE, "pj_thread_join()")); + down(&p->startstop_sem); + TRACE_((THIS_FILE, " joined!")); + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *thread) +{ + PJ_ASSERT_RETURN(thread != NULL, PJ_EINVALIDOP); + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec) +{ + pj_highprec_t ticks; + pj_thread_t *thread = pj_thread_this(); + + PJ_ASSERT_RETURN(thread != NULL, PJ_EBUG); + + /* Use high precision calculation to make sure we don't + * crop values: + * + * ticks = HZ * msec / 1000 + */ + ticks = HZ; + pj_highprec_mul(ticks, msec); + pj_highprec_div(ticks, 1000); + + TRACE_((THIS_FILE, "this thread will sleep for %u ticks", ticks)); + interruptible_sleep_on_timeout( &thread->queue, ticks); + return PJ_SUCCESS; +} + + +/////////////////////////////////////////////////////////////////////////////// +PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, + pj_atomic_value_t value, + pj_atomic_t **ptr_var) +{ + pj_atomic_t *t = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t)); + if (!t) return PJ_ENOMEM; + + atomic_set(&t->atom, value); + *ptr_var = t; + + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var ) +{ + return 0; +} + +PJ_DEF(pj_atomic_value_t) pj_atomic_set(pj_atomic_t *var, + pj_atomic_value_t value) +{ + pj_atomic_value_t oldval = atomic_read(&var->atom); + atomic_set(&var->atom, value); + return oldval; +} + +PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *var) +{ + return atomic_read(&var->atom); +} + +PJ_DEF(pj_atomic_value_t) pj_atomic_inc(pj_atomic_t *var) +{ + atomic_inc(&var->atom); + return atomic_read(&var->atom); +} + +PJ_DEF(pj_atomic_value_t) pj_atomic_dec(pj_atomic_t *var) +{ + atomic_dec(&var->atom); + return atomic_read(&var->atom); +} + + + +/////////////////////////////////////////////////////////////////////////////// +PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index) +{ + if (tls_id >= MAX_TLS_ID) + return PJ_ETOOMANY; + + *index = tls_id++; + + return PJ_SUCCESS; +} + +PJ_DEF(void) pj_thread_local_free(long index) +{ + pj_assert(index >= 0 && index < MAX_TLS_ID); +} + +PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value) +{ + pj_assert(index >= 0 && index < MAX_TLS_ID); + tls_values[index] = value; + return PJ_SUCCESS; +} + +PJ_DEF(void*) pj_thread_local_get(long index) +{ + pj_assert(index >= 0 && index < MAX_TLS_ID); + return tls_values[index]; +} + + +/////////////////////////////////////////////////////////////////////////////// +PJ_DEF(void) pj_enter_critical_section(void) +{ + spin_lock_irqsave(&critical_section, spinlock_flags); +} + +PJ_DEF(void) pj_leave_critical_section(void) +{ + spin_unlock_irqrestore(&critical_section, spinlock_flags); +} + + +/////////////////////////////////////////////////////////////////////////////// +PJ_DEF(pj_status_t) pj_mutex_create( pj_pool_t *pool, + const char *name, + int type, + pj_mutex_t **ptr_mutex) +{ + pj_mutex_t *mutex; + + PJ_UNUSED_ARG(name); + + mutex = pj_pool_alloc(pool, sizeof(pj_mutex_t)); + if (!mutex) + return PJ_ENOMEM; + + init_MUTEX(&mutex->sem); + + mutex->recursive = (type == PJ_MUTEX_RECURSE); + mutex->owner = NULL; + mutex->own_count = 0; + + /* Done. */ + *ptr_mutex = mutex; + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name, + pj_mutex_t **mutex ) +{ + return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex); +} + +PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool, + const char *name, + pj_mutex_t **mutex ) +{ + return pj_mutex_create( pool, name, PJ_MUTEX_RECURSE, mutex); +} + +PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex) +{ + PJ_ASSERT_RETURN(mutex, PJ_EINVAL); + + if (mutex->recursive) { + pj_thread_t *this_thread = pj_thread_this(); + if (mutex->owner == this_thread) { + ++mutex->own_count; + } else { + down(&mutex->sem); + pj_assert(mutex->own_count == 0); + mutex->owner = this_thread; + mutex->own_count = 1; + } + } else { + down(&mutex->sem); + } + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex) +{ + long rc; + + PJ_ASSERT_RETURN(mutex, PJ_EINVAL); + + if (mutex->recursive) { + pj_thread_t *this_thread = pj_thread_this(); + if (mutex->owner == this_thread) { + ++mutex->own_count; + } else { + rc = down_interruptible(&mutex->sem); + if (rc != 0) + return PJ_RETURN_OS_ERROR(-rc); + pj_assert(mutex->own_count == 0); + mutex->owner = this_thread; + mutex->own_count = 1; + } + } else { + int rc = down_trylock(&mutex->sem); + if (rc != 0) + return PJ_RETURN_OS_ERROR(-rc); + } + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex) +{ + PJ_ASSERT_RETURN(mutex, PJ_EINVAL); + + if (mutex->recursive) { + pj_thread_t *this_thread = pj_thread_this(); + if (mutex->owner == this_thread) { + pj_assert(mutex->own_count > 0); + --mutex->own_count; + if (mutex->own_count == 0) { + mutex->owner = NULL; + up(&mutex->sem); + } + } else { + pj_assert(!"Not owner!"); + return PJ_EINVALIDOP; + } + } else { + up(&mutex->sem); + } + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex) +{ + PJ_ASSERT_RETURN(mutex != NULL, PJ_EINVAL); + + return PJ_SUCCESS; +} + +#if defined(PJ_DEBUG) && PJ_DEBUG != 0 +PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex) +{ + if (mutex->recursive) + return mutex->owner == pj_thread_this(); + else + return 1; +} +#endif /* PJ_DEBUG */ + + +#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 + +PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool, + const char *name, + unsigned initial, + unsigned max, + pj_sem_t **sem) +{ + pj_sem_t *sem; + + PJ_UNUSED_ARG(max); + + PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL); + + sem = pj_pool_alloc(pool, sizeof(pj_sem_t)); + sema_init(&sem->sem, initial); + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem) +{ + PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL); + + down(&sem->sem); + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem) +{ + int rc; + + PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL); + + rc = down_trylock(&sem->sem); + if (rc != 0) { + return PJ_RETURN_OS_ERROR(-rc); + } else { + return PJ_SUCCESS; + } +} + +PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem) +{ + PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL); + + up(&sem->sem); + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem) +{ + PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL); + + return PJ_SUCCESS; +} + +#endif /* PJ_HAS_SEMAPHORE */ + + + + diff --git a/pjlib/src/pj/os_core_unix.c b/pjlib/src/pj/os_core_unix.c index 0f4f3a99..5b19668b 100644 --- a/pjlib/src/pj/os_core_unix.c +++ b/pjlib/src/pj/os_core_unix.c @@ -1,1182 +1,1209 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/os_core_unix.c 11 10/29/05 10:27p Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pj/os_core_unix.c $ - * - * 11 10/29/05 10:27p Bennylp - * Fixed misc warnings. - * - * 10 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 9 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 -# include -#endif - -#include // getpid() -#include // errno - -#define __USE_GNU -#include - -#define THIS_FILE "osunix" - -struct pj_thread_t -{ - char obj_name[PJ_MAX_OBJ_NAME]; - pthread_t thread; - pj_thread_proc *proc; - void *arg; - - pj_mutex_t *suspended_mutex; - -#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 - pj_uint32_t stk_size; - pj_uint32_t stk_max_usage; - char *stk_start; - const char *caller_file; - int caller_line; -#endif -}; - -struct pj_atomic_t -{ - pj_mutex_t *mutex; - pj_atomic_value_t value; -}; - -struct pj_mutex_t -{ - pthread_mutex_t mutex; - char obj_name[PJ_MAX_OBJ_NAME]; -#if PJ_DEBUG - int nesting_level; - pj_thread_t *owner; -#endif -}; - -#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 -struct pj_sem_t -{ - sem_t sem; - char obj_name[PJ_MAX_OBJ_NAME]; -}; -#endif /* PJ_HAS_SEMAPHORE */ - -#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0 -struct pj_event_t -{ - char obj_name[PJ_MAX_OBJ_NAME]; -}; -#endif /* PJ_HAS_EVENT_OBJ */ - - -#if PJ_HAS_THREADS - static pj_thread_t main_thread; - static long thread_tls_id; - static pj_mutex_t critical_section; -#else -# define MAX_THREADS 32 - static int tls_flag[MAX_THREADS]; - static void *tls[MAX_THREADS]; -#endif - -static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type); - -/* - * pj_init(void). - * Init PJLIB! - */ -PJ_DEF(pj_status_t) pj_init(void) -{ - char dummy_guid[PJ_GUID_MAX_LENGTH]; - pj_str_t guid; - pj_status_t rc; - - PJ_LOG(5, ("pj_init", "Initializing PJ Library..")); - -#if PJ_HAS_THREADS - /* Init this thread's TLS. */ - if ((rc=pj_thread_init()) != 0) { - return rc; - } - - /* Critical section. */ - if ((rc=init_mutex(&critical_section, "critsec", PJ_MUTEX_SIMPLE)) != 0) - return rc; - -#endif - - /* Initialize exception ID for the pool. - * Must do so after critical section is configured. - */ - rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION); - if (rc != PJ_SUCCESS) - return rc; - - /* Init random seed. */ - pj_srand( clock() ); - - /* Startup GUID. */ - guid.ptr = dummy_guid; - pj_generate_unique_string( &guid ); - - /* Initialize exception ID for the pool. - * Must do so after critical section is configured. - */ - rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION); - if (rc != PJ_SUCCESS) - return rc; - - /* Startup timestamp */ -#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0 - { - pj_timestamp dummy_ts; - if ((rc=pj_get_timestamp(&dummy_ts)) != 0) { - return rc; - } - } -#endif - - return PJ_SUCCESS; -} - -/* - * pj_getpid(void) - */ -PJ_DEF(pj_uint32_t) pj_getpid(void) -{ - PJ_CHECK_STACK(); - return getpid(); -} - -/* - * pj_thread_register(..) - */ -PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name, - pj_thread_desc desc, - pj_thread_t **ptr_thread) -{ -#if PJ_HAS_THREADS - char stack_ptr; - pj_thread_t *thread = (pj_thread_t *)desc; - pj_str_t thread_name = pj_str((char*)cstr_thread_name); - - /* Size sanity check. */ - if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) { - pj_assert(!"Not enough pj_thread_desc size!"); - return PJ_EBUG; - } - - /* If a thread descriptor has been registered before, just return it. */ - if (pj_thread_local_get (thread_tls_id) != 0) { - *ptr_thread = (pj_thread_t*)pj_thread_local_get (thread_tls_id); - return PJ_SUCCESS; - } - - /* Initialize and set the thread entry. */ - pj_memset(desc, 0, sizeof(pj_thread_desc)); - thread->thread = pthread_self(); - - if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1) - pj_sprintf(thread->obj_name, cstr_thread_name, thread->thread); - else - pj_sprintf(thread->obj_name, "thr%p", (void*)thread->thread); - - pj_thread_local_set(thread_tls_id, thread); - -#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 - thread->stk_start = &stack_ptr; - thread->stk_size = 0xFFFFFFFFUL; - thread->stk_max_usage = 0; -#else - stack_ptr = '\0'; -#endif - - *ptr_thread = thread; - return PJ_SUCCESS; -#else - pj_thread_t *thread = (pj_thread_t*)desc; - *ptr_thread = thread; - return SUCCESS; -#endif -} - -/* - * pj_thread_init(void) - */ -pj_status_t pj_thread_init(void) -{ -#if PJ_HAS_THREADS - pj_status_t rc; - pj_thread_t *dummy; - - rc = pj_thread_local_alloc(&thread_tls_id ); - if (rc != PJ_SUCCESS) { - return rc; - } - return pj_thread_register("thr%p", (pj_uint8_t*)&main_thread, &dummy); -#else - PJ_LOG(2,(THIS_FILE, "Thread init error. Threading is not enabled!")); - return PJ_EINVALIDOP; -#endif -} - -#if PJ_HAS_THREADS -/* - * thread_main() - * - * This is the main entry for all threads. - */ -static void *thread_main(void *param) -{ - pj_thread_t *rec = param; - void *result; - -#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 - rec->stk_start = (char*)&rec; -#endif - - /* Set current thread id. */ - pj_thread_local_set(thread_tls_id, rec); - - /* Check if suspension is required. */ - if (rec->suspended_mutex) - pj_mutex_lock(rec->suspended_mutex); - - PJ_LOG(6,(rec->obj_name, "Thread started")); - - /* Call user's entry! */ - result = (void*) (*rec->proc)(rec->arg); - - /* Done. */ - PJ_LOG(6,(rec->obj_name, "Thread quitting")); - return result; -} -#endif - -/* - * pj_thread_create(...) - */ -PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, - const char *thread_name, - pj_thread_proc *proc, - void *arg, - pj_size_t stack_size, - unsigned flags, - pj_thread_t **ptr_thread) -{ -#if PJ_HAS_THREADS - pj_thread_t *rec; - int rc; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL); - - /* Create thread record and assign name for the thread */ - rec = (struct pj_thread_t*) pj_pool_zalloc(pool, sizeof(pj_thread_t)); - if (!rec) - return PJ_ENOMEM; - - /* Set name. */ - if (!thread_name) - thread_name = "thr%p"; - - if (strchr(thread_name, '%')) { - pj_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec); - } else { - strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME); - rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; - } - -#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 - rec->stk_size = stack_size ? stack_size : 0xFFFFFFFFUL; - rec->stk_max_usage = 0; -#endif - - /* Emulate suspended thread with mutex. */ - if (flags & PJ_THREAD_SUSPENDED) { - rc = pj_mutex_create_simple(pool, NULL, &rec->suspended_mutex); - if (rc != PJ_SUCCESS) - return rc; - - pj_mutex_lock(rec->suspended_mutex); - } else { - pj_assert(rec->suspended_mutex == NULL); - } - - PJ_LOG(6, (rec->obj_name, "Thread created")); - - /* Create the thread. */ - rec->proc = proc; - rec->arg = arg; - rc = pthread_create( &rec->thread, NULL, thread_main, rec); - if (rc != 0) - return PJ_RETURN_OS_ERROR(rc); - - *ptr_thread = rec; - return PJ_SUCCESS; -#else - pj_assert(!"Threading is disabled!"); - return PJ_EINVALIDOP; -#endif -} - -/* - * pj_thread-get_name() - */ -PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p) -{ -#if PJ_HAS_THREADS - pj_thread_t *rec = (pj_thread_t*)p; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(p, ""); - - return rec->obj_name; -#else - return ""; -#endif -} - -/* - * pj_thread_resume() - */ -PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p) -{ - pj_status_t rc; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(p, PJ_EINVAL); - - rc = pj_mutex_unlock(p->suspended_mutex); - - return rc; -} - -/* - * pj_thread_this() - */ -PJ_DEF(pj_thread_t*) pj_thread_this(void) -{ -#if PJ_HAS_THREADS - pj_thread_t *rec = pj_thread_local_get(thread_tls_id); - pj_assert(rec != NULL); - - /* - * MUST NOT check stack because this function is called - * by PJ_CHECK_STACK() itself!!! - * - */ - - return rec; -#else - pj_assert(!"Threading is not enabled!"); - return NULL; -#endif -} - -/* - * pj_thread_join() - */ -PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p) -{ -#if PJ_HAS_THREADS - pj_thread_t *rec = (pj_thread_t *)p; - void *ret; - int result; - - PJ_CHECK_STACK(); - - PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name)); - result = pthread_join( rec->thread, &ret); - - if (result == 0) - return PJ_SUCCESS; - else - return PJ_RETURN_OS_ERROR(result); -#else - PJ_CHECK_STACK(); - pj_assert(!"No multithreading support!"); - return PJ_EINVALIDOP; -#endif -} - -/* - * pj_thread_destroy() - */ -PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p) -{ - /* This function is used to destroy thread handle in other platforms. - * I suppose there's nothing to do here.. - */ - PJ_CHECK_STACK(); - return PJ_SUCCESS; -} - -/* - * pj_thread_sleep() - */ -PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec) -{ - PJ_CHECK_STACK(); - return usleep(msec * 1000); -} - -#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 -/* - * pj_thread_check_stack() - * Implementation for PJ_CHECK_STACK() - */ -PJ_DEF(void) pj_thread_check_stack(const char *file, int line) -{ - char stk_ptr; - pj_uint32_t usage; - pj_thread_t *thread = pj_thread_this(); - - /* Calculate current usage. */ - usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start : - thread->stk_start - &stk_ptr; - - /* Assert if stack usage is dangerously high. */ - pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128)); - - /* Keep statistic. */ - if (usage > thread->stk_max_usage) { - thread->stk_max_usage = usage; - thread->caller_file = file; - thread->caller_line = line; - } -} - -/* - * pj_thread_get_stack_max_usage() - */ -PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread) -{ - return thread->stk_max_usage; -} - -/* - * pj_thread_get_stack_info() - */ -PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread, - const char **file, - int *line ) -{ - pj_assert(thread); - - *file = thread->caller_file; - *line = thread->caller_line; - return 0; -} - -#endif /* PJ_OS_HAS_CHECK_STACK */ - -/////////////////////////////////////////////////////////////////////////////// -/* - * pj_atomic_create() - */ -PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, - pj_atomic_value_t initial, - pj_atomic_t **ptr_atomic) -{ - pj_status_t rc; - pj_atomic_t *atomic_var = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t)); - if (!atomic_var) - return PJ_ENOMEM; - -#if PJ_HAS_THREADS - rc = pj_mutex_create(pool, "atm%p", PJ_MUTEX_SIMPLE, &atomic_var->mutex); - if (rc != PJ_SUCCESS) - return rc; -#endif - atomic_var->value = initial; - - *ptr_atomic = atomic_var; - return PJ_SUCCESS; -} - -/* - * pj_atomic_destroy() - */ -PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var ) -{ - PJ_ASSERT_RETURN(atomic_var, PJ_EINVAL); -#if PJ_HAS_THREADS - return pj_mutex_destroy( atomic_var->mutex ); -#else - return 0; -#endif -} - -/* - * pj_atomic_set() - */ -PJ_DEF(pj_atomic_value_t) pj_atomic_set(pj_atomic_t *atomic_var, - pj_atomic_value_t value) -{ - pj_atomic_value_t oldval; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(atomic_var, 0); - -#if PJ_HAS_THREADS - pj_mutex_lock( atomic_var->mutex ); -#endif - oldval = atomic_var->value; - atomic_var->value = value; -#if PJ_HAS_THREADS - pj_mutex_unlock( atomic_var->mutex); -#endif - return oldval; -} - -/* - * pj_atomic_get() - */ -PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var) -{ - pj_atomic_value_t oldval; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(atomic_var, 0); - -#if PJ_HAS_THREADS - pj_mutex_lock( atomic_var->mutex ); -#endif - oldval = atomic_var->value; -#if PJ_HAS_THREADS - pj_mutex_unlock( atomic_var->mutex); -#endif - return oldval; -} - -/* - * pj_atomic_inc() - */ -PJ_DEF(pj_atomic_value_t) pj_atomic_inc(pj_atomic_t *atomic_var) -{ - pj_atomic_value_t newval; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(atomic_var, 0); - -#if PJ_HAS_THREADS - pj_mutex_lock( atomic_var->mutex ); -#endif - newval = ++atomic_var->value; -#if PJ_HAS_THREADS - pj_mutex_unlock( atomic_var->mutex); -#endif - return newval; -} - -/* - * pj_atomic_dec() - */ -PJ_DEF(pj_atomic_value_t) pj_atomic_dec(pj_atomic_t *atomic_var) -{ - pj_atomic_value_t newval; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(atomic_var, 0); - -#if PJ_HAS_THREADS - pj_mutex_lock( atomic_var->mutex ); -#endif - newval = --atomic_var->value; -#if PJ_HAS_THREADS - pj_mutex_unlock( atomic_var->mutex); -#endif - return newval; -} - - -/////////////////////////////////////////////////////////////////////////////// -/* - * pj_thread_local_alloc() - */ -PJ_DEF(pj_status_t) pj_thread_local_alloc(long *p_index) -{ -#if PJ_HAS_THREADS - pthread_key_t key; - int rc; - - PJ_ASSERT_RETURN(p_index != NULL, PJ_EINVAL); - - pj_assert( sizeof(pthread_key_t) <= sizeof(long)); - if ((rc=pthread_key_create(&key, NULL)) != 0) - return PJ_RETURN_OS_ERROR(rc); - - *p_index = key; - return PJ_SUCCESS; -#else - int i; - for (i=0; i= 0 && index < MAX_THREADS); - tls[index] = value; -#endif -} - -PJ_DEF(void*) pj_thread_local_get(long index) -{ - //Can't check stack because this function is called - //by PJ_CHECK_STACK() itself!!! - //PJ_CHECK_STACK(); -#if PJ_HAS_THREADS - return pthread_getspecific(index); -#else - pj_assert(index >= 0 && index < MAX_THREADS); - return tls[index]; -#endif -} - -/////////////////////////////////////////////////////////////////////////////// -PJ_DEF(void) pj_enter_critical_section(void) -{ -#if PJ_HAS_THREADS - pj_mutex_lock(&critical_section); -#endif -} - -PJ_DEF(void) pj_leave_critical_section(void) -{ -#if PJ_HAS_THREADS - pj_mutex_unlock(&critical_section); -#endif -} - - -/////////////////////////////////////////////////////////////////////////////// -static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type) -{ -#if PJ_HAS_THREADS - PJ_UNUSED_ARG(type); - - PJ_CHECK_STACK(); - - if (type == PJ_MUTEX_SIMPLE) { - pthread_mutex_t the_mutex = PTHREAD_MUTEX_INITIALIZER; - mutex->mutex = the_mutex; - } else { - pthread_mutex_t the_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; - mutex->mutex = the_mutex; - } - -#if PJ_DEBUG - /* Set owner. */ - mutex->nesting_level = 0; - mutex->owner = NULL; -#endif - - /* Set name. */ - if (!name) { - name = "mtx%p"; - } - if (strchr(name, '%')) { - pj_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex); - } else { - strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME); - mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; - } - - PJ_LOG(6, (mutex->obj_name, "Mutex created")); - return PJ_SUCCESS; -#else /* PJ_HAS_THREADS */ - return PJ_SUCCESS; -#endif -} - -/* - * pj_mutex_create() - */ -PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool, - const char *name, - int type, - pj_mutex_t **ptr_mutex) -{ -#if PJ_HAS_THREADS - pj_status_t rc; - pj_mutex_t *mutex; - - PJ_ASSERT_RETURN(pool && ptr_mutex, PJ_EINVAL); - - mutex = pj_pool_alloc(pool, sizeof(*mutex)); - if (!mutex) return PJ_ENOMEM; - - if ((rc=init_mutex(mutex, name, type)) != PJ_SUCCESS) - return rc; - - *ptr_mutex = mutex; - return PJ_SUCCESS; -#else /* PJ_HAS_THREADS */ - return (pj_mutex_t*)1; -#endif -} - -/* - * pj_mutex_create_simple() - */ -PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, - const char *name, - pj_mutex_t **mutex ) -{ - return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex); -} - -/* - * pj_mutex_create_recursive() - */ -PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool, - const char *name, - pj_mutex_t **mutex ) -{ - return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex); -} - -/* - * pj_mutex_lock() - */ -PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex) -{ -#if PJ_HAS_THREADS - pj_status_t status; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(mutex, PJ_EINVAL); - - PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting", - pj_thread_this()->obj_name)); - - status = pthread_mutex_lock( &mutex->mutex ); - - PJ_LOG(6,(mutex->obj_name, - (status==0 ? "Mutex acquired by thread %s" : "FAILED by %s"), - pj_thread_this()->obj_name)); - -#if PJ_DEBUG - if (status == PJ_SUCCESS) { - mutex->owner = pj_thread_this(); - ++mutex->nesting_level; - } -#endif - - if (status == 0) - return PJ_SUCCESS; - else - return PJ_RETURN_OS_ERROR(status); -#else /* PJ_HAS_THREADS */ - pj_assert( mutex == (pj_mutex_t*)1 ); - return PJ_SUCCESS; -#endif -} - -/* - * pj_mutex_unlock() - */ -PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex) -{ -#if PJ_HAS_THREADS - pj_status_t status; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(mutex, PJ_EINVAL); - -#if PJ_DEBUG - pj_assert(mutex->owner == pj_thread_this()); - if (--mutex->nesting_level == 0) { - mutex->owner = NULL; - } -#endif - - PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s", - pj_thread_this()->obj_name)); - - status = pthread_mutex_unlock( &mutex->mutex ); - if (status == 0) - return PJ_SUCCESS; - else - return PJ_RETURN_OS_ERROR(status); - -#else /* PJ_HAS_THREADS */ - pj_assert( mutex == (pj_mutex_t*)1 ); - return PJ_SUCCESS; -#endif -} - -/* - * pj_mutex_trylock() - */ -PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex) -{ -#if PJ_HAS_THREADS - int status; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(mutex, PJ_EINVAL); - - status = pthread_mutex_trylock( &mutex->mutex ); - - if (status==0) { - PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s", - pj_thread_this()->obj_name)); - -#if PJ_DEBUG - mutex->owner = pj_thread_this(); - ++mutex->nesting_level; -#endif - } - - if (status==0) - return PJ_SUCCESS; - else - return PJ_RETURN_OS_ERROR(status); -#else /* PJ_HAS_THREADS */ - pj_assert( mutex == (pj_mutex_t*)1); - return PJ_SUCCESS; -#endif -} - -/* - * pj_mutex_destroy() - */ -PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex) -{ - int status; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(mutex, PJ_EINVAL); - -#if PJ_HAS_THREADS - PJ_LOG(6,(mutex->obj_name, "Mutex destroyed")); - status = pthread_mutex_destroy( &mutex->mutex ); - if (status == 0) - return PJ_SUCCESS; - else - return PJ_RETURN_OS_ERROR(status); -#else - pj_assert( mutex == (pj_mutex_t*)1 ); - status = PJ_SUCCESS; - return status; -#endif -} - -#if PJ_DEBUG -PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex) -{ -#if PJ_HAS_THREADS - return mutex->owner == pj_thread_this(); -#else - return 1; -#endif -} -#endif - -/////////////////////////////////////////////////////////////////////////////// -#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 - -/* - * pj_sem_create() - */ -PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool, - const char *name, - unsigned initial, - unsigned max, - pj_sem_t **ptr_sem) -{ -#if PJ_HAS_THREADS - pj_sem_t *sem; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(pool != NULL && ptr_sem != NULL, PJ_EINVAL); - - sem = pj_pool_alloc(pool, sizeof(*sem)); - if (!sem) return PJ_ENOMEM; - - if (sem_init( &sem->sem, 0, initial) != 0) - return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); - - /* Set name. */ - if (!name) { - name = "sem%p"; - } - if (strchr(name, '%')) { - pj_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem); - } else { - strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME); - sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; - } - - PJ_LOG(6, (sem->obj_name, "Semaphore created")); - - *ptr_sem = sem; - return PJ_SUCCESS; -#else - *ptr_sem = (pj_sem_t*)1; - return PJ_SUCCESS; -#endif -} - -/* - * pj_sem_wait() - */ -PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem) -{ -#if PJ_HAS_THREADS - int result; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(sem, PJ_EINVAL); - - PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting", - pj_thread_this()->obj_name)); - - result = sem_wait( &sem->sem ); - - if (result == 0) { - PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", - pj_thread_this()->obj_name)); - } else { - PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire", - pj_thread_this()->obj_name)); - } - - if (result == 0) - return PJ_SUCCESS; - else - return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); -#else - pj_assert( sem == (pj_sem_t*) 1 ); - return PJ_SUCCESS; -#endif -} - -/* - * pj_sem_trywait() - */ -PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem) -{ -#if PJ_HAS_THREADS - int result; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(sem, PJ_EINVAL); - - result = sem_trywait( &sem->sem ); - - if (result == 0) { - PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", - pj_thread_this()->obj_name)); - } - if (result == 0) - return PJ_SUCCESS; - else - return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); -#else - pj_assert( sem == (pj_sem_t*)1 ); - return PJ_SUCCESS; -#endif -} - -/* - * pj_sem_post() - */ -PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem) -{ -#if PJ_HAS_THREADS - int result; - PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s", - pj_thread_this()->obj_name)); - result = sem_post( &sem->sem ); - - if (result == 0) - return PJ_SUCCESS; - else - return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); -#else - pj_assert( sem == (pj_sem_t*) 1); - return PJ_SUCCESS; -#endif -} - -/* - * pj_sem_destroy() - */ -PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem) -{ -#if PJ_HAS_THREADS - int result; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(sem, PJ_EINVAL); - - PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s", - pj_thread_this()->obj_name)); - result = sem_destroy( &sem->sem ); - - if (result == 0) - return PJ_SUCCESS; - else - return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); -#else - pj_assert( sem == (pj_sem_t*) 1 ); - return PJ_SUCCESS; -#endif -} - -#endif /* PJ_HAS_SEMAPHORE */ - -/////////////////////////////////////////////////////////////////////////////// -#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0 - -/* - * pj_event_create() - */ -PJ_DEF(pj_status_t) pj_event_create(pj_pool_t *pool, const char *name, - pj_bool_t manual_reset, pj_bool_t initial, - pj_event_t **ptr_event) -{ - pj_assert(!"Not supported!"); - PJ_UNUSED_ARG(pool); - PJ_UNUSED_ARG(name); - PJ_UNUSED_ARG(manual_reset); - PJ_UNUSED_ARG(initial); - PJ_UNUSED_ARG(ptr_event); - return PJ_EINVALIDOP; -} - -/* - * pj_event_wait() - */ -PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event) -{ - PJ_UNUSED_ARG(event); - return PJ_EINVALIDOP; -} - -/* - * pj_event_trywait() - */ -PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event) -{ - PJ_UNUSED_ARG(event); - return PJ_EINVALIDOP; -} - -/* - * pj_event_set() - */ -PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event) -{ - PJ_UNUSED_ARG(event); - return PJ_EINVALIDOP; -} - -/* - * pj_event_pulse() - */ -PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event) -{ - PJ_UNUSED_ARG(event); - return PJ_EINVALIDOP; -} - -/* - * pj_event_reset() - */ -PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event) -{ - PJ_UNUSED_ARG(event); - return PJ_EINVALIDOP; -} - -/* - * pj_event_destroy() - */ -PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event) -{ - PJ_UNUSED_ARG(event); - return PJ_EINVALIDOP; -} - -#endif /* PJ_HAS_EVENT_OBJ */ - -/////////////////////////////////////////////////////////////////////////////// -#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0 -/* - * Terminal - */ - -/** - * Set terminal color. - */ -PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color) -{ - PJ_UNUSED_ARG(color); - return PJ_EINVALIDOP; -} - -/** - * Get current terminal foreground color. - */ -PJ_DEF(pj_color_t) pj_term_get_color(void) -{ - return 0; -} - -#endif /* PJ_TERM_HAS_COLOR */ - +/* $Header: /pjproject-0.3/pjlib/src/pj/os_core_unix.c 11 10/29/05 10:27p Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pj/os_core_unix.c $ + * + * 11 10/29/05 10:27p Bennylp + * Fixed misc warnings. + * + * 10 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 9 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 +# include +#endif + +#include // getpid() +#include // errno + +#define __USE_GNU +#include + +#define THIS_FILE "osunix" + +struct pj_thread_t +{ + char obj_name[PJ_MAX_OBJ_NAME]; + pthread_t thread; + pj_thread_proc *proc; + void *arg; + + pj_mutex_t *suspended_mutex; + +#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 + pj_uint32_t stk_size; + pj_uint32_t stk_max_usage; + char *stk_start; + const char *caller_file; + int caller_line; +#endif +}; + +struct pj_atomic_t +{ + pj_mutex_t *mutex; + pj_atomic_value_t value; +}; + +struct pj_mutex_t +{ + pthread_mutex_t mutex; + char obj_name[PJ_MAX_OBJ_NAME]; +#if PJ_DEBUG + int nesting_level; + pj_thread_t *owner; +#endif +}; + +#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 +struct pj_sem_t +{ + sem_t sem; + char obj_name[PJ_MAX_OBJ_NAME]; +}; +#endif /* PJ_HAS_SEMAPHORE */ + +#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0 +struct pj_event_t +{ + char obj_name[PJ_MAX_OBJ_NAME]; +}; +#endif /* PJ_HAS_EVENT_OBJ */ + + +#if PJ_HAS_THREADS + static pj_thread_t main_thread; + static long thread_tls_id; + static pj_mutex_t critical_section; +#else +# define MAX_THREADS 32 + static int tls_flag[MAX_THREADS]; + static void *tls[MAX_THREADS]; +#endif + +static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type); + +/* + * pj_init(void). + * Init PJLIB! + */ +PJ_DEF(pj_status_t) pj_init(void) +{ + char dummy_guid[PJ_GUID_MAX_LENGTH]; + pj_str_t guid; + pj_status_t rc; + + PJ_LOG(5, ("pj_init", "Initializing PJ Library..")); + +#if PJ_HAS_THREADS + /* Init this thread's TLS. */ + if ((rc=pj_thread_init()) != 0) { + return rc; + } + + /* Critical section. */ + if ((rc=init_mutex(&critical_section, "critsec", PJ_MUTEX_SIMPLE)) != 0) + return rc; + +#endif + + /* Initialize exception ID for the pool. + * Must do so after critical section is configured. + */ + rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION); + if (rc != PJ_SUCCESS) + return rc; + + /* Init random seed. */ + pj_srand( clock() ); + + /* Startup GUID. */ + guid.ptr = dummy_guid; + pj_generate_unique_string( &guid ); + + /* Initialize exception ID for the pool. + * Must do so after critical section is configured. + */ + rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION); + if (rc != PJ_SUCCESS) + return rc; + + /* Startup timestamp */ +#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0 + { + pj_timestamp dummy_ts; + if ((rc=pj_get_timestamp(&dummy_ts)) != 0) { + return rc; + } + } +#endif + + return PJ_SUCCESS; +} + +/* + * pj_getpid(void) + */ +PJ_DEF(pj_uint32_t) pj_getpid(void) +{ + PJ_CHECK_STACK(); + return getpid(); +} + +/* + * pj_thread_register(..) + */ +PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name, + pj_thread_desc desc, + pj_thread_t **ptr_thread) +{ +#if PJ_HAS_THREADS + char stack_ptr; + pj_status_t rc; + pj_thread_t *thread = (pj_thread_t *)desc; + pj_str_t thread_name = pj_str((char*)cstr_thread_name); + + /* Size sanity check. */ + if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) { + pj_assert(!"Not enough pj_thread_desc size!"); + return PJ_EBUG; + } + + /* If a thread descriptor has been registered before, just return it. */ + if (pj_thread_local_get (thread_tls_id) != 0) { + *ptr_thread = (pj_thread_t*)pj_thread_local_get (thread_tls_id); + return PJ_SUCCESS; + } + + /* Initialize and set the thread entry. */ + pj_memset(desc, 0, sizeof(struct pj_thread_t)); + thread->thread = pthread_self(); + + if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1) + pj_sprintf(thread->obj_name, cstr_thread_name, thread->thread); + else + pj_sprintf(thread->obj_name, "thr%p", (void*)thread->thread); + + rc = pj_thread_local_set(thread_tls_id, thread); + if (rc != PJ_SUCCESS) + return rc; + +#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 + thread->stk_start = &stack_ptr; + thread->stk_size = 0xFFFFFFFFUL; + thread->stk_max_usage = 0; +#else + stack_ptr = '\0'; +#endif + + *ptr_thread = thread; + return PJ_SUCCESS; +#else + pj_thread_t *thread = (pj_thread_t*)desc; + *ptr_thread = thread; + return PJ_SUCCESS; +#endif +} + +/* + * pj_thread_init(void) + */ +pj_status_t pj_thread_init(void) +{ +#if PJ_HAS_THREADS + pj_status_t rc; + pj_thread_t *dummy; + + rc = pj_thread_local_alloc(&thread_tls_id ); + if (rc != PJ_SUCCESS) { + return rc; + } + return pj_thread_register("thr%p", (long*)&main_thread, &dummy); +#else + PJ_LOG(2,(THIS_FILE, "Thread init error. Threading is not enabled!")); + return PJ_EINVALIDOP; +#endif +} + +#if PJ_HAS_THREADS +/* + * thread_main() + * + * This is the main entry for all threads. + */ +static void *thread_main(void *param) +{ + pj_thread_t *rec = param; + void *result; + pj_status_t rc; + +#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 + rec->stk_start = (char*)&rec; +#endif + + /* Set current thread id. */ + rc = pj_thread_local_set(thread_tls_id, rec); + if (rc != PJ_SUCCESS) { + pj_assert(!"Thread TLS ID is not set (pj_init() error?)"); + } + + /* Check if suspension is required. */ + if (rec->suspended_mutex) + pj_mutex_lock(rec->suspended_mutex); + + PJ_LOG(6,(rec->obj_name, "Thread started")); + + /* Call user's entry! */ + result = (void*) (*rec->proc)(rec->arg); + + /* Done. */ + PJ_LOG(6,(rec->obj_name, "Thread quitting")); + return result; +} +#endif + +/* + * pj_thread_create(...) + */ +PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, + const char *thread_name, + pj_thread_proc *proc, + void *arg, + pj_size_t stack_size, + unsigned flags, + pj_thread_t **ptr_thread) +{ +#if PJ_HAS_THREADS + pj_thread_t *rec; + int rc; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL); + + /* Create thread record and assign name for the thread */ + rec = (struct pj_thread_t*) pj_pool_zalloc(pool, sizeof(pj_thread_t)); + if (!rec) + return PJ_ENOMEM; + + /* Set name. */ + if (!thread_name) + thread_name = "thr%p"; + + if (strchr(thread_name, '%')) { + pj_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec); + } else { + strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME); + rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; + } + +#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 + rec->stk_size = stack_size ? stack_size : 0xFFFFFFFFUL; + rec->stk_max_usage = 0; +#endif + + /* Emulate suspended thread with mutex. */ + if (flags & PJ_THREAD_SUSPENDED) { + rc = pj_mutex_create_simple(pool, NULL, &rec->suspended_mutex); + if (rc != PJ_SUCCESS) + return rc; + + pj_mutex_lock(rec->suspended_mutex); + } else { + pj_assert(rec->suspended_mutex == NULL); + } + + PJ_LOG(6, (rec->obj_name, "Thread created")); + + /* Create the thread. */ + rec->proc = proc; + rec->arg = arg; + rc = pthread_create( &rec->thread, NULL, thread_main, rec); + if (rc != 0) + return PJ_RETURN_OS_ERROR(rc); + + *ptr_thread = rec; + return PJ_SUCCESS; +#else + pj_assert(!"Threading is disabled!"); + return PJ_EINVALIDOP; +#endif +} + +/* + * pj_thread-get_name() + */ +PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p) +{ +#if PJ_HAS_THREADS + pj_thread_t *rec = (pj_thread_t*)p; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(p, ""); + + return rec->obj_name; +#else + return ""; +#endif +} + +/* + * pj_thread_resume() + */ +PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p) +{ + pj_status_t rc; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(p, PJ_EINVAL); + + rc = pj_mutex_unlock(p->suspended_mutex); + + return rc; +} + +/* + * pj_thread_this() + */ +PJ_DEF(pj_thread_t*) pj_thread_this(void) +{ +#if PJ_HAS_THREADS + pj_thread_t *rec = pj_thread_local_get(thread_tls_id); + pj_assert(rec != NULL); + + /* + * MUST NOT check stack because this function is called + * by PJ_CHECK_STACK() itself!!! + * + */ + + return rec; +#else + pj_assert(!"Threading is not enabled!"); + return NULL; +#endif +} + +/* + * pj_thread_join() + */ +PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p) +{ +#if PJ_HAS_THREADS + pj_thread_t *rec = (pj_thread_t *)p; + void *ret; + int result; + + PJ_CHECK_STACK(); + + PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name)); + result = pthread_join( rec->thread, &ret); + + if (result == 0) + return PJ_SUCCESS; + else + return PJ_RETURN_OS_ERROR(result); +#else + PJ_CHECK_STACK(); + pj_assert(!"No multithreading support!"); + return PJ_EINVALIDOP; +#endif +} + +/* + * pj_thread_destroy() + */ +PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p) +{ + /* This function is used to destroy thread handle in other platforms. + * I suppose there's nothing to do here.. + */ + PJ_CHECK_STACK(); + return PJ_SUCCESS; +} + +/* + * pj_thread_sleep() + */ +PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec) +{ + PJ_CHECK_STACK(); + return usleep(msec * 1000); +} + +#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 +/* + * pj_thread_check_stack() + * Implementation for PJ_CHECK_STACK() + */ +PJ_DEF(void) pj_thread_check_stack(const char *file, int line) +{ + char stk_ptr; + pj_uint32_t usage; + pj_thread_t *thread = pj_thread_this(); + + /* Calculate current usage. */ + usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start : + thread->stk_start - &stk_ptr; + + /* Assert if stack usage is dangerously high. */ + pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128)); + + /* Keep statistic. */ + if (usage > thread->stk_max_usage) { + thread->stk_max_usage = usage; + thread->caller_file = file; + thread->caller_line = line; + } +} + +/* + * pj_thread_get_stack_max_usage() + */ +PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread) +{ + return thread->stk_max_usage; +} + +/* + * pj_thread_get_stack_info() + */ +PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread, + const char **file, + int *line ) +{ + pj_assert(thread); + + *file = thread->caller_file; + *line = thread->caller_line; + return 0; +} + +#endif /* PJ_OS_HAS_CHECK_STACK */ + +/////////////////////////////////////////////////////////////////////////////// +/* + * pj_atomic_create() + */ +PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, + pj_atomic_value_t initial, + pj_atomic_t **ptr_atomic) +{ + pj_status_t rc; + pj_atomic_t *atomic_var = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t)); + if (!atomic_var) + return PJ_ENOMEM; + +#if PJ_HAS_THREADS + rc = pj_mutex_create(pool, "atm%p", PJ_MUTEX_SIMPLE, &atomic_var->mutex); + if (rc != PJ_SUCCESS) + return rc; +#endif + atomic_var->value = initial; + + *ptr_atomic = atomic_var; + return PJ_SUCCESS; +} + +/* + * pj_atomic_destroy() + */ +PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var ) +{ + PJ_ASSERT_RETURN(atomic_var, PJ_EINVAL); +#if PJ_HAS_THREADS + return pj_mutex_destroy( atomic_var->mutex ); +#else + return 0; +#endif +} + +/* + * pj_atomic_set() + */ +PJ_DEF(pj_atomic_value_t) pj_atomic_set(pj_atomic_t *atomic_var, + pj_atomic_value_t value) +{ + pj_atomic_value_t oldval; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(atomic_var, 0); + +#if PJ_HAS_THREADS + pj_mutex_lock( atomic_var->mutex ); +#endif + oldval = atomic_var->value; + atomic_var->value = value; +#if PJ_HAS_THREADS + pj_mutex_unlock( atomic_var->mutex); +#endif + return oldval; +} + +/* + * pj_atomic_get() + */ +PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var) +{ + pj_atomic_value_t oldval; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(atomic_var, 0); + +#if PJ_HAS_THREADS + pj_mutex_lock( atomic_var->mutex ); +#endif + oldval = atomic_var->value; +#if PJ_HAS_THREADS + pj_mutex_unlock( atomic_var->mutex); +#endif + return oldval; +} + +/* + * pj_atomic_inc() + */ +PJ_DEF(pj_atomic_value_t) pj_atomic_inc(pj_atomic_t *atomic_var) +{ + pj_atomic_value_t newval; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(atomic_var, 0); + +#if PJ_HAS_THREADS + pj_mutex_lock( atomic_var->mutex ); +#endif + newval = ++atomic_var->value; +#if PJ_HAS_THREADS + pj_mutex_unlock( atomic_var->mutex); +#endif + return newval; +} + +/* + * pj_atomic_dec() + */ +PJ_DEF(pj_atomic_value_t) pj_atomic_dec(pj_atomic_t *atomic_var) +{ + pj_atomic_value_t newval; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(atomic_var, 0); + +#if PJ_HAS_THREADS + pj_mutex_lock( atomic_var->mutex ); +#endif + newval = --atomic_var->value; +#if PJ_HAS_THREADS + pj_mutex_unlock( atomic_var->mutex); +#endif + return newval; +} + + +/////////////////////////////////////////////////////////////////////////////// +/* + * pj_thread_local_alloc() + */ +PJ_DEF(pj_status_t) pj_thread_local_alloc(long *p_index) +{ +#if PJ_HAS_THREADS + pthread_key_t key; + int rc; + + PJ_ASSERT_RETURN(p_index != NULL, PJ_EINVAL); + + pj_assert( sizeof(pthread_key_t) <= sizeof(long)); + if ((rc=pthread_key_create(&key, NULL)) != 0) + return PJ_RETURN_OS_ERROR(rc); + + *p_index = key; + return PJ_SUCCESS; +#else + int i; + for (i=0; i= 0 && index < MAX_THREADS); + tls[index] = value; + return PJ_SUCCESS; +#endif +} + +PJ_DEF(void*) pj_thread_local_get(long index) +{ + //Can't check stack because this function is called + //by PJ_CHECK_STACK() itself!!! + //PJ_CHECK_STACK(); +#if PJ_HAS_THREADS + return pthread_getspecific(index); +#else + pj_assert(index >= 0 && index < MAX_THREADS); + return tls[index]; +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +PJ_DEF(void) pj_enter_critical_section(void) +{ +#if PJ_HAS_THREADS + pj_mutex_lock(&critical_section); +#endif +} + +PJ_DEF(void) pj_leave_critical_section(void) +{ +#if PJ_HAS_THREADS + pj_mutex_unlock(&critical_section); +#endif +} + + +/////////////////////////////////////////////////////////////////////////////// +static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type) +{ +#if PJ_HAS_THREADS + pthread_mutexattr_t attr; + int rc; + + PJ_CHECK_STACK(); + + pthread_mutexattr_init(&attr); + + if (type == PJ_MUTEX_SIMPLE) { +#if defined(PJ_LINUX) && PJ_LINUX!=0 + rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_FAST_NP); +#else + rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); +#endif + } else { +#if defined(PJ_LINUX) && PJ_LINUX!=0 + rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); +#else + rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); +#endif + } + + if (rc != 0) { + return PJ_RETURN_OS_ERROR(rc); + } + + rc = pthread_mutex_init(&mutex->mutex, &attr); + if (rc != 0) { + return PJ_RETURN_OS_ERROR(rc); + } + +#if PJ_DEBUG + /* Set owner. */ + mutex->nesting_level = 0; + mutex->owner = NULL; +#endif + + /* Set name. */ + if (!name) { + name = "mtx%p"; + } + if (strchr(name, '%')) { + pj_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex); + } else { + strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME); + mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; + } + + PJ_LOG(6, (mutex->obj_name, "Mutex created")); + return PJ_SUCCESS; +#else /* PJ_HAS_THREADS */ + return PJ_SUCCESS; +#endif +} + +/* + * pj_mutex_create() + */ +PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool, + const char *name, + int type, + pj_mutex_t **ptr_mutex) +{ +#if PJ_HAS_THREADS + pj_status_t rc; + pj_mutex_t *mutex; + + PJ_ASSERT_RETURN(pool && ptr_mutex, PJ_EINVAL); + + mutex = pj_pool_alloc(pool, sizeof(*mutex)); + if (!mutex) return PJ_ENOMEM; + + if ((rc=init_mutex(mutex, name, type)) != PJ_SUCCESS) + return rc; + + *ptr_mutex = mutex; + return PJ_SUCCESS; +#else /* PJ_HAS_THREADS */ + return (pj_mutex_t*)1; +#endif +} + +/* + * pj_mutex_create_simple() + */ +PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, + const char *name, + pj_mutex_t **mutex ) +{ + return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex); +} + +/* + * pj_mutex_create_recursive() + */ +PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool, + const char *name, + pj_mutex_t **mutex ) +{ + return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex); +} + +/* + * pj_mutex_lock() + */ +PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex) +{ +#if PJ_HAS_THREADS + pj_status_t status; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(mutex, PJ_EINVAL); + + PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting", + pj_thread_this()->obj_name)); + + status = pthread_mutex_lock( &mutex->mutex ); + + PJ_LOG(6,(mutex->obj_name, + (status==0 ? "Mutex acquired by thread %s" : "FAILED by %s"), + pj_thread_this()->obj_name)); + +#if PJ_DEBUG + if (status == PJ_SUCCESS) { + mutex->owner = pj_thread_this(); + ++mutex->nesting_level; + } +#endif + + if (status == 0) + return PJ_SUCCESS; + else + return PJ_RETURN_OS_ERROR(status); +#else /* PJ_HAS_THREADS */ + pj_assert( mutex == (pj_mutex_t*)1 ); + return PJ_SUCCESS; +#endif +} + +/* + * pj_mutex_unlock() + */ +PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex) +{ +#if PJ_HAS_THREADS + pj_status_t status; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(mutex, PJ_EINVAL); + +#if PJ_DEBUG + pj_assert(mutex->owner == pj_thread_this()); + if (--mutex->nesting_level == 0) { + mutex->owner = NULL; + } +#endif + + PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s", + pj_thread_this()->obj_name)); + + status = pthread_mutex_unlock( &mutex->mutex ); + if (status == 0) + return PJ_SUCCESS; + else + return PJ_RETURN_OS_ERROR(status); + +#else /* PJ_HAS_THREADS */ + pj_assert( mutex == (pj_mutex_t*)1 ); + return PJ_SUCCESS; +#endif +} + +/* + * pj_mutex_trylock() + */ +PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex) +{ +#if PJ_HAS_THREADS + int status; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(mutex, PJ_EINVAL); + + status = pthread_mutex_trylock( &mutex->mutex ); + + if (status==0) { + PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s", + pj_thread_this()->obj_name)); + +#if PJ_DEBUG + mutex->owner = pj_thread_this(); + ++mutex->nesting_level; +#endif + } + + if (status==0) + return PJ_SUCCESS; + else + return PJ_RETURN_OS_ERROR(status); +#else /* PJ_HAS_THREADS */ + pj_assert( mutex == (pj_mutex_t*)1); + return PJ_SUCCESS; +#endif +} + +/* + * pj_mutex_destroy() + */ +PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex) +{ + int status; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(mutex, PJ_EINVAL); + +#if PJ_HAS_THREADS + PJ_LOG(6,(mutex->obj_name, "Mutex destroyed")); + status = pthread_mutex_destroy( &mutex->mutex ); + if (status == 0) + return PJ_SUCCESS; + else + return PJ_RETURN_OS_ERROR(status); +#else + pj_assert( mutex == (pj_mutex_t*)1 ); + status = PJ_SUCCESS; + return status; +#endif +} + +#if PJ_DEBUG +PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex) +{ +#if PJ_HAS_THREADS + return mutex->owner == pj_thread_this(); +#else + return 1; +#endif +} +#endif + +/////////////////////////////////////////////////////////////////////////////// +#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 + +/* + * pj_sem_create() + */ +PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool, + const char *name, + unsigned initial, + unsigned max, + pj_sem_t **ptr_sem) +{ +#if PJ_HAS_THREADS + pj_sem_t *sem; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(pool != NULL && ptr_sem != NULL, PJ_EINVAL); + + sem = pj_pool_alloc(pool, sizeof(*sem)); + if (!sem) return PJ_ENOMEM; + + if (sem_init( &sem->sem, 0, initial) != 0) + return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); + + /* Set name. */ + if (!name) { + name = "sem%p"; + } + if (strchr(name, '%')) { + pj_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem); + } else { + strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME); + sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; + } + + PJ_LOG(6, (sem->obj_name, "Semaphore created")); + + *ptr_sem = sem; + return PJ_SUCCESS; +#else + *ptr_sem = (pj_sem_t*)1; + return PJ_SUCCESS; +#endif +} + +/* + * pj_sem_wait() + */ +PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem) +{ +#if PJ_HAS_THREADS + int result; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(sem, PJ_EINVAL); + + PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting", + pj_thread_this()->obj_name)); + + result = sem_wait( &sem->sem ); + + if (result == 0) { + PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", + pj_thread_this()->obj_name)); + } else { + PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire", + pj_thread_this()->obj_name)); + } + + if (result == 0) + return PJ_SUCCESS; + else + return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); +#else + pj_assert( sem == (pj_sem_t*) 1 ); + return PJ_SUCCESS; +#endif +} + +/* + * pj_sem_trywait() + */ +PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem) +{ +#if PJ_HAS_THREADS + int result; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(sem, PJ_EINVAL); + + result = sem_trywait( &sem->sem ); + + if (result == 0) { + PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", + pj_thread_this()->obj_name)); + } + if (result == 0) + return PJ_SUCCESS; + else + return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); +#else + pj_assert( sem == (pj_sem_t*)1 ); + return PJ_SUCCESS; +#endif +} + +/* + * pj_sem_post() + */ +PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem) +{ +#if PJ_HAS_THREADS + int result; + PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s", + pj_thread_this()->obj_name)); + result = sem_post( &sem->sem ); + + if (result == 0) + return PJ_SUCCESS; + else + return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); +#else + pj_assert( sem == (pj_sem_t*) 1); + return PJ_SUCCESS; +#endif +} + +/* + * pj_sem_destroy() + */ +PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem) +{ +#if PJ_HAS_THREADS + int result; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(sem, PJ_EINVAL); + + PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s", + pj_thread_this()->obj_name)); + result = sem_destroy( &sem->sem ); + + if (result == 0) + return PJ_SUCCESS; + else + return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); +#else + pj_assert( sem == (pj_sem_t*) 1 ); + return PJ_SUCCESS; +#endif +} + +#endif /* PJ_HAS_SEMAPHORE */ + +/////////////////////////////////////////////////////////////////////////////// +#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0 + +/* + * pj_event_create() + */ +PJ_DEF(pj_status_t) pj_event_create(pj_pool_t *pool, const char *name, + pj_bool_t manual_reset, pj_bool_t initial, + pj_event_t **ptr_event) +{ + pj_assert(!"Not supported!"); + PJ_UNUSED_ARG(pool); + PJ_UNUSED_ARG(name); + PJ_UNUSED_ARG(manual_reset); + PJ_UNUSED_ARG(initial); + PJ_UNUSED_ARG(ptr_event); + return PJ_EINVALIDOP; +} + +/* + * pj_event_wait() + */ +PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event) +{ + PJ_UNUSED_ARG(event); + return PJ_EINVALIDOP; +} + +/* + * pj_event_trywait() + */ +PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event) +{ + PJ_UNUSED_ARG(event); + return PJ_EINVALIDOP; +} + +/* + * pj_event_set() + */ +PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event) +{ + PJ_UNUSED_ARG(event); + return PJ_EINVALIDOP; +} + +/* + * pj_event_pulse() + */ +PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event) +{ + PJ_UNUSED_ARG(event); + return PJ_EINVALIDOP; +} + +/* + * pj_event_reset() + */ +PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event) +{ + PJ_UNUSED_ARG(event); + return PJ_EINVALIDOP; +} + +/* + * pj_event_destroy() + */ +PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event) +{ + PJ_UNUSED_ARG(event); + return PJ_EINVALIDOP; +} + +#endif /* PJ_HAS_EVENT_OBJ */ + +/////////////////////////////////////////////////////////////////////////////// +#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0 +/* + * Terminal + */ + +/** + * Set terminal color. + */ +PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color) +{ + PJ_UNUSED_ARG(color); + return PJ_EINVALIDOP; +} + +/** + * Get current terminal foreground color. + */ +PJ_DEF(pj_color_t) pj_term_get_color(void) +{ + return 0; +} + +#endif /* PJ_TERM_HAS_COLOR */ + diff --git a/pjlib/src/pj/os_core_win32.c b/pjlib/src/pj/os_core_win32.c index dd892b5d..1c37b044 100644 --- a/pjlib/src/pj/os_core_win32.c +++ b/pjlib/src/pj/os_core_win32.c @@ -1,1182 +1,1191 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/os_core_win32.c 12 10/29/05 11:51a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/os_core_win32.c $ - * - * 12 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 11 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 10 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 9 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0 -# include -#endif - -#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0 -# include -#endif - -/* - * Implementation of pj_thread_t. - */ -struct pj_thread_t -{ - char obj_name[PJ_MAX_OBJ_NAME]; - HANDLE hthread; - DWORD idthread; - pj_thread_proc *proc; - void *arg; - -#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 - pj_uint32_t stk_size; - pj_uint32_t stk_max_usage; - char *stk_start; - const char *caller_file; - int caller_line; -#endif -}; - - -/* - * Implementation of pj_mutex_t. - */ -struct pj_mutex_t -{ -#if PJ_WIN32_WINNT >= 0x0400 - CRITICAL_SECTION crit; -#else - HANDLE hMutex; -#endif - char obj_name[PJ_MAX_OBJ_NAME]; -#if PJ_DEBUG - int nesting_level; - pj_thread_t *owner; -#endif -}; - -/* - * Implementation of pj_sem_t. - */ -typedef struct pj_sem_t -{ - HANDLE hSemaphore; - char obj_name[PJ_MAX_OBJ_NAME]; -} pj_mem_t; - - -/* - * Implementation of pj_event_t. - */ -struct pj_event_t -{ - HANDLE hEvent; - char obj_name[PJ_MAX_OBJ_NAME]; -}; - -/* - * Implementation of pj_atomic_t. - */ -struct pj_atomic_t -{ - long value; -}; - -/* - * Static global variables. - */ -static pj_thread_desc main_thread; -static long thread_tls_id; -static pj_mutex_t critical_section_mutex; - - -/* - * Some static prototypes. - */ -static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name); - - -/* - * pj_init(void). - * Init PJLIB! - */ -PJ_DEF(pj_status_t) pj_init(void) -{ - WSADATA wsa; - char dummy_guid[32]; /* use maximum GUID length */ - pj_str_t guid; - pj_status_t rc; - - PJ_LOG(5, ("pj_init", "Initializing PJ Library..")); - - /* Init Winsock.. */ - if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) { - PJ_LOG(1, ("pj_init", "Winsock initialization has returned an error")); - return PJ_RETURN_OS_ERROR(WSAGetLastError()); - } - - /* Init this thread's TLS. */ - if ((rc=pj_thread_init()) != PJ_SUCCESS) { - PJ_LOG(1, ("pj_init", "Thread initialization has returned an error")); - return rc; - } - - /* Init random seed. */ - pj_srand( GetCurrentProcessId() ); - - /* Startup GUID. */ - guid.ptr = dummy_guid; - pj_generate_unique_string( &guid ); - - /* Initialize critical section. */ - if ((rc=init_mutex(&critical_section_mutex, "pj%p")) != PJ_SUCCESS) - return rc; - - /* Initialize exception ID for the pool. - * Must do so after critical section is configured. - */ - rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION); - if (rc != PJ_SUCCESS) - return rc; - - /* Startup timestamp */ -#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0 - { - pj_timestamp dummy_ts; - if ((rc=pj_get_timestamp(&dummy_ts)) != PJ_SUCCESS) { - PJ_LOG(1, ("pj_init", "Unable to initialize timestamp")); - return rc; - } - } -#endif - - return PJ_SUCCESS; -} - -/* - * pj_getpid(void) - */ -PJ_DEF(pj_uint32_t) pj_getpid(void) -{ - PJ_CHECK_STACK(); - return GetCurrentProcessId(); -} - -/* - * pj_thread_register(..) - */ -PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name, - pj_thread_desc desc, - pj_thread_t **thread_ptr) -{ - char stack_ptr; - pj_thread_t *thread = (pj_thread_t *)desc; - pj_str_t thread_name = pj_str((char*)cstr_thread_name); - - /* Size sanity check. */ - if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) { - pj_assert(!"Not enough pj_thread_desc size!"); - return PJ_EBUG; - } - - /* If a thread descriptor has been registered before, just return it. */ - if (pj_thread_local_get (thread_tls_id) != 0) { - *thread_ptr = (pj_thread_t*)pj_thread_local_get (thread_tls_id); - return PJ_SUCCESS; - } - - /* Initialize and set the thread entry. */ - pj_memset(desc, 0, sizeof(pj_thread_desc)); - thread->hthread = GetCurrentThread(); - thread->idthread = GetCurrentThreadId(); - -#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 - thread->stk_start = &stack_ptr; - thread->stk_size = 0xFFFFFFFFUL; - thread->stk_max_usage = 0; -#else - stack_ptr = '\0'; -#endif - - if (cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1) - pj_sprintf(thread->obj_name, cstr_thread_name, thread->idthread); - else - pj_sprintf(thread->obj_name, "thr%p", (void*)thread->idthread); - - pj_thread_local_set(thread_tls_id, thread); - - *thread_ptr = thread; - return PJ_SUCCESS; -} - -/* - * pj_thread_init(void) - */ -pj_status_t pj_thread_init(void) -{ - pj_status_t rc; - pj_thread_t *thread; - - rc = pj_thread_local_alloc(&thread_tls_id); - if (rc != PJ_SUCCESS) - return rc; - - return pj_thread_register("thr%p", main_thread, &thread); -} - -static DWORD WINAPI thread_main(void *param) -{ - pj_thread_t *rec = param; - DWORD result; - -#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 - rec->stk_start = (char*)&rec; -#endif - - PJ_LOG(6,(rec->obj_name, "Thread started")); - - pj_thread_local_set(thread_tls_id, rec); - result = (*rec->proc)(rec->arg); - - PJ_LOG(6,(rec->obj_name, "Thread quitting")); - return (DWORD)result; -} - -/* - * pj_thread_create(...) - */ -PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, - const char *thread_name, - pj_thread_proc *proc, - void *arg, - pj_size_t stack_size, - unsigned flags, - pj_thread_t **thread_ptr) -{ - DWORD dwflags = 0; - pj_thread_t *rec; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(pool && proc && thread_ptr, PJ_EINVAL); - - /* Set flags */ - if (flags & PJ_THREAD_SUSPENDED) - dwflags |= CREATE_SUSPENDED; - - /* Create thread record and assign name for the thread */ - rec = (struct pj_thread_t*) pj_pool_calloc(pool, 1, sizeof(pj_thread_t)); - if (!rec) - return PJ_ENOMEM; - - /* Set name. */ - if (!thread_name) - thread_name = "thr%p"; - - if (strchr(thread_name, '%')) { - pj_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec); - } else { - strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME); - rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; - } - - PJ_LOG(6, (rec->obj_name, "Thread created")); - -#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 - rec->stk_size = stack_size ? stack_size : 0xFFFFFFFFUL; - rec->stk_max_usage = 0; -#endif - - /* Create the thread. */ - rec->proc = proc; - rec->arg = arg; - rec->hthread = CreateThread(NULL, stack_size, - thread_main, rec, - dwflags, &rec->idthread); - if (rec->hthread == NULL) - return PJ_RETURN_OS_ERROR(GetLastError()); - - /* Success! */ - *thread_ptr = rec; - return PJ_SUCCESS; -} - -/* - * pj_thread-get_name() - */ -PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p) -{ - pj_thread_t *rec = (pj_thread_t*)p; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(p, ""); - - return rec->obj_name; -} - -/* - * pj_thread_resume() - */ -PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p) -{ - pj_thread_t *rec = (pj_thread_t*)p; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(p, PJ_EINVAL); - - if (ResumeThread(rec->hthread) == (DWORD)-1) - return PJ_RETURN_OS_ERROR(GetLastError()); - else - return PJ_SUCCESS; -} - -/* - * pj_thread_this() - */ -PJ_DEF(pj_thread_t*) pj_thread_this(void) -{ - pj_thread_t *rec = pj_thread_local_get(thread_tls_id); - pj_assert(rec != NULL); - - /* - * MUST NOT check stack because this function is called - * by PJ_CHECK_STACK() itself!!! - * - */ - - return rec; -} - -/* - * pj_thread_join() - */ -PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p) -{ - pj_thread_t *rec = (pj_thread_t *)p; - DWORD rc; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(p, PJ_EINVAL); - - PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name)); - - rc = WaitForSingleObject(rec->hthread, INFINITE); - - if (rc==WAIT_OBJECT_0) - return PJ_SUCCESS; - else if (rc==WAIT_TIMEOUT) - return PJ_ETIMEDOUT; - else - return PJ_RETURN_OS_ERROR(GetLastError()); -} - -/* - * pj_thread_destroy() - */ -PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p) -{ - pj_thread_t *rec = (pj_thread_t *)p; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(p, PJ_EINVAL); - - if (CloseHandle(rec->hthread) == TRUE) - return PJ_SUCCESS; - else - return PJ_RETURN_OS_ERROR(GetLastError()); -} - -/* - * pj_thread_sleep() - */ -PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec) -{ - PJ_CHECK_STACK(); - Sleep(msec); - return PJ_SUCCESS; -} - -#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0 -/* - * pj_thread_check_stack() - * Implementation for PJ_CHECK_STACK() - */ -PJ_DEF(void) pj_thread_check_stack(const char *file, int line) -{ - char stk_ptr; - pj_uint32_t usage; - pj_thread_t *thread = pj_thread_this(); - - pj_assert(thread); - - /* Calculate current usage. */ - usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start : - thread->stk_start - &stk_ptr; - - /* Assert if stack usage is dangerously high. */ - pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128)); - - /* Keep statistic. */ - if (usage > thread->stk_max_usage) { - thread->stk_max_usage = usage; - thread->caller_file = file; - thread->caller_line = line; - } - -} - -/* - * pj_thread_get_stack_max_usage() - */ -PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread) -{ - return thread->stk_max_usage; -} - -/* - * pj_thread_get_stack_info() - */ -PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread, - const char **file, - int *line ) -{ - pj_assert(thread); - - *file = thread->caller_file; - *line = thread->caller_line; - return 0; -} - -#endif /* PJ_OS_HAS_CHECK_STACK */ - - -/////////////////////////////////////////////////////////////////////////////// - -/* - * pj_atomic_create() - */ -PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, - pj_atomic_value_t initial, - pj_atomic_t **atomic_ptr) -{ - pj_atomic_t *atomic_var = pj_pool_alloc(pool, sizeof(pj_atomic_t)); - if (!atomic_var) - return PJ_ENOMEM; - - atomic_var->value = initial; - *atomic_ptr = atomic_var; - - return PJ_SUCCESS; -} - -/* - * pj_atomic_destroy() - */ -PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var ) -{ - PJ_UNUSED_ARG(var); - PJ_ASSERT_RETURN(var, PJ_EINVAL); - - return 0; -} - -/* - * pj_atomic_set() - */ -PJ_DEF(long) pj_atomic_set(pj_atomic_t *atomic_var, long value) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(atomic_var, 0); - - return InterlockedExchange(&atomic_var->value, value); -} - -/* - * pj_atomic_get() - */ -PJ_DEF(long) pj_atomic_get(pj_atomic_t *atomic_var) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(atomic_var, 0); - - return atomic_var->value; -} - -/* - * pj_atomic_inc() - */ -PJ_DEF(long) pj_atomic_inc(pj_atomic_t *atomic_var) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(atomic_var, 0); - -#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400 - return InterlockedIncrement(&atomic_var->value); -#else -# error Fix Me -#endif -} - -/* - * pj_atomic_dec() - */ -PJ_DEF(long) pj_atomic_dec(pj_atomic_t *atomic_var) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(atomic_var, 0); - -#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400 - return InterlockedDecrement(&atomic_var->value); -#else -# error Fix me -#endif -} - - -/////////////////////////////////////////////////////////////////////////////// -/* - * pj_thread_local_alloc() - */ -PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index) -{ - PJ_ASSERT_RETURN(index != NULL, PJ_EINVAL); - - //Can't check stack because this function is called in the - //beginning before main thread is initialized. - //PJ_CHECK_STACK(); - - *index = TlsAlloc(); - - if (*index == TLS_OUT_OF_INDEXES) - return PJ_RETURN_OS_ERROR(GetLastError()); - else - return PJ_SUCCESS; -} - -/* - * pj_thread_local_free() - */ -PJ_DEF(void) pj_thread_local_free(long index) -{ - PJ_CHECK_STACK(); - TlsFree(index); -} - -/* - * pj_thread_local_set() - */ -PJ_DEF(void) pj_thread_local_set(long index, void *value) -{ - //Can't check stack because this function is called in the - //beginning before main thread is initialized. - //PJ_CHECK_STACK(); - TlsSetValue(index, value); -} - -/* - * pj_thread_local_get() - */ -PJ_DEF(void*) pj_thread_local_get(long index) -{ - //Can't check stack because this function is called - //by PJ_CHECK_STACK() itself!!! - //PJ_CHECK_STACK(); - return TlsGetValue(index); -} - -/////////////////////////////////////////////////////////////////////////////// -static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name) -{ - - PJ_CHECK_STACK(); - -#if PJ_WIN32_WINNT >= 0x0400 - InitializeCriticalSection(&mutex->crit); -#else - mutex->hMutex = CreateMutex(NULL, FALSE, NULL); - if (!mutex->hMutex) { - return PJ_RETURN_OS_ERROR(GetLastError()); - } -#endif - -#if PJ_DEBUG - /* Set owner. */ - mutex->nesting_level = 0; - mutex->owner = NULL; -#endif - - /* Set name. */ - if (!name) { - name = "mtx%p"; - } - if (strchr(name, '%')) { - pj_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex); - } else { - strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME); - mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; - } - - PJ_LOG(6, (mutex->obj_name, "Mutex created")); - return PJ_SUCCESS; -} - -/* - * pj_mutex_create() - */ -PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool, - const char *name, - int type, - pj_mutex_t **mutex_ptr) -{ - pj_status_t rc; - pj_mutex_t *mutex; - - PJ_UNUSED_ARG(type); - PJ_ASSERT_RETURN(pool && mutex_ptr, PJ_EINVAL); - - mutex = pj_pool_alloc(pool, sizeof(*mutex)); - if (!mutex) - return PJ_ENOMEM; - - rc = init_mutex(mutex, name); - if (rc != PJ_SUCCESS) - return rc; - - *mutex_ptr = mutex; - - return PJ_SUCCESS; -} - -/* - * pj_mutex_create_simple() - */ -PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, - const char *name, - pj_mutex_t **mutex ) -{ - return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex); -} - -/* - * pj_mutex_create_recursive() - */ -PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool, - const char *name, - pj_mutex_t **mutex ) -{ - return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex); -} - -/* - * pj_mutex_lock() - */ -PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex) -{ - pj_status_t status; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(mutex, PJ_EINVAL); - - PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting", - pj_thread_this()->obj_name)); - -#if PJ_WIN32_WINNT >= 0x0400 - EnterCriticalSection(&mutex->crit); - status=PJ_SUCCESS; -#else - if (WaitForSingleObject(mutex->hMutex, INFINITE)==WAIT_OBJECT_0) - status = PJ_SUCCESS; - else - status = PJ_STATUS_FROM_OS(GetLastError()); - -#endif - PJ_LOG(6,(mutex->obj_name, - (status==PJ_SUCCESS ? "Mutex acquired by thread %s" : "FAILED by %s"), - pj_thread_this()->obj_name)); - -#if PJ_DEBUG - if (status == PJ_SUCCESS) { - mutex->owner = pj_thread_this(); - ++mutex->nesting_level; - } -#endif - - return status; -} - -/* - * pj_mutex_unlock() - */ -PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex) -{ - pj_status_t status; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(mutex, PJ_EINVAL); - -#if PJ_DEBUG - pj_assert(mutex->owner == pj_thread_this()); - if (--mutex->nesting_level == 0) { - mutex->owner = NULL; - } -#endif - - PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s", - pj_thread_this()->obj_name)); - -#if PJ_WIN32_WINNT >= 0x0400 - LeaveCriticalSection(&mutex->crit); - status=PJ_SUCCESS; -#else - status = ReleaseMutex(mutex->hMutex) ? PJ_SUCCESS : - PJ_STATUS_FROM_OS(GetLastError()); -#endif - return status; -} - -/* - * pj_mutex_trylock() - */ -PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex) -{ - pj_status_t status; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(mutex, PJ_EINVAL); - -#if PJ_WIN32_WINNT >= 0x0400 - status=TryEnterCriticalSection(&mutex->crit) ? PJ_SUCCESS : PJ_EUNKNOWN; -#else - status = WaitForSingleObject(mutex->hMutex, 0)==WAIT_OBJECT_0 ? - PJ_SUCCESS : PJ_ETIMEDOUT; -#endif - if (status==PJ_SUCCESS) { - PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s", - pj_thread_this()->obj_name)); - -#if PJ_DEBUG - mutex->owner = pj_thread_this(); - ++mutex->nesting_level; -#endif - } - return status; -} - -/* - * pj_mutex_destroy() - */ -PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(mutex, PJ_EINVAL); - - PJ_LOG(6,(mutex->obj_name, "Mutex destroyed")); - -#if PJ_WIN32_WINNT >= 0x0400 - DeleteCriticalSection(&mutex->crit); - return PJ_SUCCESS; -#else - return CloseHandle(mutex->hMutex) ? PJ_SUCCESS : - PJ_RETURN_OS_ERROR(GetLastError()); -#endif -} - -#if PJ_DEBUG -/* - * pj_mutex_is_locked() - */ -PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex) -{ - return mutex->owner == pj_thread_this(); -} -#endif - -/////////////////////////////////////////////////////////////////////////////// -/* - * pj_enter_critical_section() - */ -PJ_DEF(void) pj_enter_critical_section(void) -{ - pj_mutex_lock(&critical_section_mutex); -} - - -/* - * pj_leave_critical_section() - */ -PJ_DEF(void) pj_leave_critical_section(void) -{ - pj_mutex_unlock(&critical_section_mutex); -} - -/////////////////////////////////////////////////////////////////////////////// -#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 - -/* - * pj_sem_create() - */ -PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool, - const char *name, - unsigned initial, - unsigned max, - pj_sem_t **sem_ptr) -{ - pj_sem_t *sem; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(pool && sem_ptr, PJ_EINVAL); - - sem = pj_pool_alloc(pool, sizeof(*sem)); - sem->hSemaphore = CreateSemaphore(NULL, initial, max, NULL); - if (!sem->hSemaphore) - return PJ_RETURN_OS_ERROR(GetLastError()); - - /* Set name. */ - if (!name) { - name = "sem%p"; - } - if (strchr(name, '%')) { - pj_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem); - } else { - strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME); - sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; - } - - PJ_LOG(6, (sem->obj_name, "Semaphore created")); - - *sem_ptr = sem; - return PJ_SUCCESS; -} - -static pj_status_t pj_sem_wait_for(pj_sem_t *sem, unsigned timeout) -{ - DWORD result; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(sem, PJ_EINVAL); - - PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting", - pj_thread_this()->obj_name)); - - result = WaitForSingleObject(sem->hSemaphore, timeout); - if (result == WAIT_OBJECT_0) { - PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", - pj_thread_this()->obj_name)); - } else { - PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire", - pj_thread_this()->obj_name)); - } - - if (result==WAIT_OBJECT_0) - return PJ_SUCCESS; - else if (result==WAIT_TIMEOUT) - return PJ_ETIMEDOUT; - else - return PJ_RETURN_OS_ERROR(GetLastError()); -} - -/* - * pj_sem_wait() - */ -PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(sem, PJ_EINVAL); - - return pj_sem_wait_for(sem, INFINITE); -} - -/* - * pj_sem_trywait() - */ -PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(sem, PJ_EINVAL); - - return pj_sem_wait_for(sem, 0); -} - -/* - * pj_sem_post() - */ -PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(sem, PJ_EINVAL); - - PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s", - pj_thread_this()->obj_name)); - - if (ReleaseSemaphore(sem->hSemaphore, 1, NULL)) - return PJ_SUCCESS; - else - return PJ_RETURN_OS_ERROR(GetLastError()); -} - -/* - * pj_sem_destroy() - */ -PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(sem, PJ_EINVAL); - - PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s", - pj_thread_this()->obj_name)); - - if (CloseHandle(sem->hSemaphore)) - return PJ_SUCCESS; - else - return PJ_RETURN_OS_ERROR(GetLastError()); -} - -#endif /* PJ_HAS_SEMAPHORE */ -/////////////////////////////////////////////////////////////////////////////// - - -#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0 - -/* - * pj_event_create() - */ -PJ_DEF(pj_status_t) pj_event_create( pj_pool_t *pool, - const char *name, - pj_bool_t manual_reset, - pj_bool_t initial, - pj_event_t **event_ptr) -{ - pj_event_t *event; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(pool && event_ptr, PJ_EINVAL); - - event = pj_pool_alloc(pool, sizeof(*event)); - if (!event) - return PJ_ENOMEM; - - event->hEvent = CreateEvent(NULL, manual_reset?TRUE:FALSE, - initial?TRUE:FALSE, NULL); - - if (!event->hEvent) - return PJ_RETURN_OS_ERROR(GetLastError()); - - /* Set name. */ - if (!name) { - name = "evt%p"; - } - if (strchr(name, '%')) { - pj_snprintf(event->obj_name, PJ_MAX_OBJ_NAME, name, event); - } else { - strncpy(event->obj_name, name, PJ_MAX_OBJ_NAME); - event->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; - } - - PJ_LOG(6, (event->obj_name, "Event created")); - - *event_ptr = event; - return PJ_SUCCESS; -} - -static pj_status_t pj_event_wait_for(pj_event_t *event, unsigned timeout) -{ - DWORD result; - - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(event, PJ_EINVAL); - - PJ_LOG(6, (event->obj_name, "Event: thread %s is waiting", - pj_thread_this()->obj_name)); - - result = WaitForSingleObject(event->hEvent, timeout); - if (result == WAIT_OBJECT_0) { - PJ_LOG(6, (event->obj_name, "Event: thread %s is released", - pj_thread_this()->obj_name)); - } else { - PJ_LOG(6, (event->obj_name, "Event: thread %s FAILED to acquire", - pj_thread_this()->obj_name)); - } - - if (result==WAIT_OBJECT_0) - return PJ_SUCCESS; - else if (result==WAIT_TIMEOUT) - return PJ_ETIMEDOUT; - else - return PJ_RETURN_OS_ERROR(GetLastError()); -} - -/* - * pj_event_wait() - */ -PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event) -{ - PJ_ASSERT_RETURN(event, PJ_EINVAL); - - return pj_event_wait_for(event, INFINITE); -} - -/* - * pj_event_trywait() - */ -PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event) -{ - PJ_ASSERT_RETURN(event, PJ_EINVAL); - - return pj_event_wait_for(event, 0); -} - -/* - * pj_event_set() - */ -PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(event, PJ_EINVAL); - - PJ_LOG(6, (event->obj_name, "Setting event")); - - if (SetEvent(event->hEvent)) - return PJ_SUCCESS; - else - return PJ_RETURN_OS_ERROR(GetLastError()); -} - -/* - * pj_event_pulse() - */ -PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(event, PJ_EINVAL); - - PJ_LOG(6, (event->obj_name, "Pulsing event")); - - if (PulseEvent(event->hEvent)) - return PJ_SUCCESS; - else - return PJ_RETURN_OS_ERROR(GetLastError()); -} - -/* - * pj_event_reset() - */ -PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(event, PJ_EINVAL); - - PJ_LOG(6, (event->obj_name, "Event is reset")); - - if (ResetEvent(event->hEvent)) - return PJ_SUCCESS; - else - return PJ_RETURN_OS_ERROR(GetLastError()); -} - -/* - * pj_event_destroy() - */ -PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(event, PJ_EINVAL); - - PJ_LOG(6, (event->obj_name, "Event is destroying")); - - if (CloseHandle(event->hEvent)) - return PJ_SUCCESS; - else - return PJ_RETURN_OS_ERROR(GetLastError()); -} - -#endif /* PJ_HAS_EVENT_OBJ */ - -/////////////////////////////////////////////////////////////////////////////// -#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0 -/* - * Terminal color - */ - -static WORD pj_color_to_os_attr(pj_color_t color) -{ - WORD attr = 0; - - if (color & PJ_TERM_COLOR_R) - attr |= FOREGROUND_RED; - if (color & PJ_TERM_COLOR_G) - attr |= FOREGROUND_GREEN; - if (color & PJ_TERM_COLOR_B) - attr |= FOREGROUND_BLUE; - if (color & PJ_TERM_COLOR_BRIGHT) - attr |= FOREGROUND_INTENSITY; - - return attr; -} - -static pj_color_t os_attr_to_pj_color(WORD attr) -{ - int color = 0; - - if (attr & FOREGROUND_RED) - color |= PJ_TERM_COLOR_R; - if (attr & FOREGROUND_GREEN) - color |= PJ_TERM_COLOR_G; - if (attr & FOREGROUND_BLUE) - color |= PJ_TERM_COLOR_B; - if (attr & FOREGROUND_INTENSITY) - color |= PJ_TERM_COLOR_BRIGHT; - - return color; -} - - -/* - * pj_term_set_color() - */ -PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color) -{ - BOOL rc; - WORD attr = 0; - - PJ_CHECK_STACK(); - - attr = pj_color_to_os_attr(color); - rc = SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), attr); - return rc ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError()); -} - -/* - * pj_term_get_color() - * Get current terminal foreground color. - */ -PJ_DEF(pj_color_t) pj_term_get_color(void) -{ - CONSOLE_SCREEN_BUFFER_INFO info; - - PJ_CHECK_STACK(); - - GetConsoleScreenBufferInfo( GetStdHandle(STD_OUTPUT_HANDLE), &info); - return os_attr_to_pj_color(info.wAttributes); -} - -#endif /* PJ_TERM_HAS_COLOR */ +/* $Header: /pjproject-0.3/pjlib/src/pj/os_core_win32.c 12 10/29/05 11:51a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/os_core_win32.c $ + * + * 12 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 11 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 10 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 9 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0 +# include +#endif + +#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0 +# include +#endif + +/* + * Implementation of pj_thread_t. + */ +struct pj_thread_t +{ + char obj_name[PJ_MAX_OBJ_NAME]; + HANDLE hthread; + DWORD idthread; + pj_thread_proc *proc; + void *arg; + +#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 + pj_uint32_t stk_size; + pj_uint32_t stk_max_usage; + char *stk_start; + const char *caller_file; + int caller_line; +#endif +}; + + +/* + * Implementation of pj_mutex_t. + */ +struct pj_mutex_t +{ +#if PJ_WIN32_WINNT >= 0x0400 + CRITICAL_SECTION crit; +#else + HANDLE hMutex; +#endif + char obj_name[PJ_MAX_OBJ_NAME]; +#if PJ_DEBUG + int nesting_level; + pj_thread_t *owner; +#endif +}; + +/* + * Implementation of pj_sem_t. + */ +typedef struct pj_sem_t +{ + HANDLE hSemaphore; + char obj_name[PJ_MAX_OBJ_NAME]; +} pj_mem_t; + + +/* + * Implementation of pj_event_t. + */ +struct pj_event_t +{ + HANDLE hEvent; + char obj_name[PJ_MAX_OBJ_NAME]; +}; + +/* + * Implementation of pj_atomic_t. + */ +struct pj_atomic_t +{ + long value; +}; + +/* + * Static global variables. + */ +static pj_thread_desc main_thread; +static long thread_tls_id; +static pj_mutex_t critical_section_mutex; + + +/* + * Some static prototypes. + */ +static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name); + + +/* + * pj_init(void). + * Init PJLIB! + */ +PJ_DEF(pj_status_t) pj_init(void) +{ + WSADATA wsa; + char dummy_guid[32]; /* use maximum GUID length */ + pj_str_t guid; + pj_status_t rc; + + PJ_LOG(5, ("pj_init", "Initializing PJ Library..")); + + /* Init Winsock.. */ + if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) { + PJ_LOG(1, ("pj_init", "Winsock initialization has returned an error")); + return PJ_RETURN_OS_ERROR(WSAGetLastError()); + } + + /* Init this thread's TLS. */ + if ((rc=pj_thread_init()) != PJ_SUCCESS) { + PJ_LOG(1, ("pj_init", "Thread initialization has returned an error")); + return rc; + } + + /* Init random seed. */ + pj_srand( GetCurrentProcessId() ); + + /* Startup GUID. */ + guid.ptr = dummy_guid; + pj_generate_unique_string( &guid ); + + /* Initialize critical section. */ + if ((rc=init_mutex(&critical_section_mutex, "pj%p")) != PJ_SUCCESS) + return rc; + + /* Initialize exception ID for the pool. + * Must do so after critical section is configured. + */ + rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION); + if (rc != PJ_SUCCESS) + return rc; + + /* Startup timestamp */ +#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0 + { + pj_timestamp dummy_ts; + if ((rc=pj_get_timestamp(&dummy_ts)) != PJ_SUCCESS) { + PJ_LOG(1, ("pj_init", "Unable to initialize timestamp")); + return rc; + } + } +#endif + + return PJ_SUCCESS; +} + +/* + * pj_getpid(void) + */ +PJ_DEF(pj_uint32_t) pj_getpid(void) +{ + PJ_CHECK_STACK(); + return GetCurrentProcessId(); +} + +/* + * pj_thread_register(..) + */ +PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name, + pj_thread_desc desc, + pj_thread_t **thread_ptr) +{ + char stack_ptr; + pj_status_t rc; + pj_thread_t *thread = (pj_thread_t *)desc; + pj_str_t thread_name = pj_str((char*)cstr_thread_name); + + /* Size sanity check. */ + if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) { + pj_assert(!"Not enough pj_thread_desc size!"); + return PJ_EBUG; + } + + /* If a thread descriptor has been registered before, just return it. */ + if (pj_thread_local_get (thread_tls_id) != 0) { + *thread_ptr = (pj_thread_t*)pj_thread_local_get (thread_tls_id); + return PJ_SUCCESS; + } + + /* Initialize and set the thread entry. */ + pj_memset(desc, 0, sizeof(struct pj_thread_t)); + thread->hthread = GetCurrentThread(); + thread->idthread = GetCurrentThreadId(); + +#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 + thread->stk_start = &stack_ptr; + thread->stk_size = 0xFFFFFFFFUL; + thread->stk_max_usage = 0; +#else + stack_ptr = '\0'; +#endif + + if (cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1) + pj_sprintf(thread->obj_name, cstr_thread_name, thread->idthread); + else + pj_sprintf(thread->obj_name, "thr%p", (void*)thread->idthread); + + rc = pj_thread_local_set(thread_tls_id, thread); + if (rc != PJ_SUCCESS) + return rc; + + *thread_ptr = thread; + return PJ_SUCCESS; +} + +/* + * pj_thread_init(void) + */ +pj_status_t pj_thread_init(void) +{ + pj_status_t rc; + pj_thread_t *thread; + + rc = pj_thread_local_alloc(&thread_tls_id); + if (rc != PJ_SUCCESS) + return rc; + + return pj_thread_register("thr%p", main_thread, &thread); +} + +static DWORD WINAPI thread_main(void *param) +{ + pj_thread_t *rec = param; + DWORD result; + +#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 + rec->stk_start = (char*)&rec; +#endif + + PJ_LOG(6,(rec->obj_name, "Thread started")); + + if (pj_thread_local_set(thread_tls_id, rec) != PJ_SUCCESS) { + pj_assert(!"TLS is not set (pj_init() error?)"); + } + + result = (*rec->proc)(rec->arg); + + PJ_LOG(6,(rec->obj_name, "Thread quitting")); + return (DWORD)result; +} + +/* + * pj_thread_create(...) + */ +PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, + const char *thread_name, + pj_thread_proc *proc, + void *arg, + pj_size_t stack_size, + unsigned flags, + pj_thread_t **thread_ptr) +{ + DWORD dwflags = 0; + pj_thread_t *rec; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(pool && proc && thread_ptr, PJ_EINVAL); + + /* Set flags */ + if (flags & PJ_THREAD_SUSPENDED) + dwflags |= CREATE_SUSPENDED; + + /* Create thread record and assign name for the thread */ + rec = (struct pj_thread_t*) pj_pool_calloc(pool, 1, sizeof(pj_thread_t)); + if (!rec) + return PJ_ENOMEM; + + /* Set name. */ + if (!thread_name) + thread_name = "thr%p"; + + if (strchr(thread_name, '%')) { + pj_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec); + } else { + strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME); + rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; + } + + PJ_LOG(6, (rec->obj_name, "Thread created")); + +#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 + rec->stk_size = stack_size ? stack_size : 0xFFFFFFFFUL; + rec->stk_max_usage = 0; +#endif + + /* Create the thread. */ + rec->proc = proc; + rec->arg = arg; + rec->hthread = CreateThread(NULL, stack_size, + thread_main, rec, + dwflags, &rec->idthread); + if (rec->hthread == NULL) + return PJ_RETURN_OS_ERROR(GetLastError()); + + /* Success! */ + *thread_ptr = rec; + return PJ_SUCCESS; +} + +/* + * pj_thread-get_name() + */ +PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p) +{ + pj_thread_t *rec = (pj_thread_t*)p; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(p, ""); + + return rec->obj_name; +} + +/* + * pj_thread_resume() + */ +PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p) +{ + pj_thread_t *rec = (pj_thread_t*)p; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(p, PJ_EINVAL); + + if (ResumeThread(rec->hthread) == (DWORD)-1) + return PJ_RETURN_OS_ERROR(GetLastError()); + else + return PJ_SUCCESS; +} + +/* + * pj_thread_this() + */ +PJ_DEF(pj_thread_t*) pj_thread_this(void) +{ + pj_thread_t *rec = pj_thread_local_get(thread_tls_id); + pj_assert(rec != NULL); + + /* + * MUST NOT check stack because this function is called + * by PJ_CHECK_STACK() itself!!! + * + */ + + return rec; +} + +/* + * pj_thread_join() + */ +PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p) +{ + pj_thread_t *rec = (pj_thread_t *)p; + DWORD rc; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(p, PJ_EINVAL); + + PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name)); + + rc = WaitForSingleObject(rec->hthread, INFINITE); + + if (rc==WAIT_OBJECT_0) + return PJ_SUCCESS; + else if (rc==WAIT_TIMEOUT) + return PJ_ETIMEDOUT; + else + return PJ_RETURN_OS_ERROR(GetLastError()); +} + +/* + * pj_thread_destroy() + */ +PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p) +{ + pj_thread_t *rec = (pj_thread_t *)p; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(p, PJ_EINVAL); + + if (CloseHandle(rec->hthread) == TRUE) + return PJ_SUCCESS; + else + return PJ_RETURN_OS_ERROR(GetLastError()); +} + +/* + * pj_thread_sleep() + */ +PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec) +{ + PJ_CHECK_STACK(); + Sleep(msec); + return PJ_SUCCESS; +} + +#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0 +/* + * pj_thread_check_stack() + * Implementation for PJ_CHECK_STACK() + */ +PJ_DEF(void) pj_thread_check_stack(const char *file, int line) +{ + char stk_ptr; + pj_uint32_t usage; + pj_thread_t *thread = pj_thread_this(); + + pj_assert(thread); + + /* Calculate current usage. */ + usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start : + thread->stk_start - &stk_ptr; + + /* Assert if stack usage is dangerously high. */ + pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128)); + + /* Keep statistic. */ + if (usage > thread->stk_max_usage) { + thread->stk_max_usage = usage; + thread->caller_file = file; + thread->caller_line = line; + } + +} + +/* + * pj_thread_get_stack_max_usage() + */ +PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread) +{ + return thread->stk_max_usage; +} + +/* + * pj_thread_get_stack_info() + */ +PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread, + const char **file, + int *line ) +{ + pj_assert(thread); + + *file = thread->caller_file; + *line = thread->caller_line; + return 0; +} + +#endif /* PJ_OS_HAS_CHECK_STACK */ + + +/////////////////////////////////////////////////////////////////////////////// + +/* + * pj_atomic_create() + */ +PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, + pj_atomic_value_t initial, + pj_atomic_t **atomic_ptr) +{ + pj_atomic_t *atomic_var = pj_pool_alloc(pool, sizeof(pj_atomic_t)); + if (!atomic_var) + return PJ_ENOMEM; + + atomic_var->value = initial; + *atomic_ptr = atomic_var; + + return PJ_SUCCESS; +} + +/* + * pj_atomic_destroy() + */ +PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var ) +{ + PJ_UNUSED_ARG(var); + PJ_ASSERT_RETURN(var, PJ_EINVAL); + + return 0; +} + +/* + * pj_atomic_set() + */ +PJ_DEF(long) pj_atomic_set(pj_atomic_t *atomic_var, long value) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(atomic_var, 0); + + return InterlockedExchange(&atomic_var->value, value); +} + +/* + * pj_atomic_get() + */ +PJ_DEF(long) pj_atomic_get(pj_atomic_t *atomic_var) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(atomic_var, 0); + + return atomic_var->value; +} + +/* + * pj_atomic_inc() + */ +PJ_DEF(long) pj_atomic_inc(pj_atomic_t *atomic_var) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(atomic_var, 0); + +#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400 + return InterlockedIncrement(&atomic_var->value); +#else +# error Fix Me +#endif +} + +/* + * pj_atomic_dec() + */ +PJ_DEF(long) pj_atomic_dec(pj_atomic_t *atomic_var) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(atomic_var, 0); + +#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400 + return InterlockedDecrement(&atomic_var->value); +#else +# error Fix me +#endif +} + + +/////////////////////////////////////////////////////////////////////////////// +/* + * pj_thread_local_alloc() + */ +PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index) +{ + PJ_ASSERT_RETURN(index != NULL, PJ_EINVAL); + + //Can't check stack because this function is called in the + //beginning before main thread is initialized. + //PJ_CHECK_STACK(); + + *index = TlsAlloc(); + + if (*index == TLS_OUT_OF_INDEXES) + return PJ_RETURN_OS_ERROR(GetLastError()); + else + return PJ_SUCCESS; +} + +/* + * pj_thread_local_free() + */ +PJ_DEF(void) pj_thread_local_free(long index) +{ + PJ_CHECK_STACK(); + TlsFree(index); +} + +/* + * pj_thread_local_set() + */ +PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value) +{ + BOOL rc; + + //Can't check stack because this function is called in the + //beginning before main thread is initialized. + //PJ_CHECK_STACK(); + rc = TlsSetValue(index, value); + return rc!=0 ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError()); +} + +/* + * pj_thread_local_get() + */ +PJ_DEF(void*) pj_thread_local_get(long index) +{ + //Can't check stack because this function is called + //by PJ_CHECK_STACK() itself!!! + //PJ_CHECK_STACK(); + return TlsGetValue(index); +} + +/////////////////////////////////////////////////////////////////////////////// +static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name) +{ + + PJ_CHECK_STACK(); + +#if PJ_WIN32_WINNT >= 0x0400 + InitializeCriticalSection(&mutex->crit); +#else + mutex->hMutex = CreateMutex(NULL, FALSE, NULL); + if (!mutex->hMutex) { + return PJ_RETURN_OS_ERROR(GetLastError()); + } +#endif + +#if PJ_DEBUG + /* Set owner. */ + mutex->nesting_level = 0; + mutex->owner = NULL; +#endif + + /* Set name. */ + if (!name) { + name = "mtx%p"; + } + if (strchr(name, '%')) { + pj_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex); + } else { + strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME); + mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; + } + + PJ_LOG(6, (mutex->obj_name, "Mutex created")); + return PJ_SUCCESS; +} + +/* + * pj_mutex_create() + */ +PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool, + const char *name, + int type, + pj_mutex_t **mutex_ptr) +{ + pj_status_t rc; + pj_mutex_t *mutex; + + PJ_UNUSED_ARG(type); + PJ_ASSERT_RETURN(pool && mutex_ptr, PJ_EINVAL); + + mutex = pj_pool_alloc(pool, sizeof(*mutex)); + if (!mutex) + return PJ_ENOMEM; + + rc = init_mutex(mutex, name); + if (rc != PJ_SUCCESS) + return rc; + + *mutex_ptr = mutex; + + return PJ_SUCCESS; +} + +/* + * pj_mutex_create_simple() + */ +PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, + const char *name, + pj_mutex_t **mutex ) +{ + return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex); +} + +/* + * pj_mutex_create_recursive() + */ +PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool, + const char *name, + pj_mutex_t **mutex ) +{ + return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex); +} + +/* + * pj_mutex_lock() + */ +PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex) +{ + pj_status_t status; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(mutex, PJ_EINVAL); + + PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting", + pj_thread_this()->obj_name)); + +#if PJ_WIN32_WINNT >= 0x0400 + EnterCriticalSection(&mutex->crit); + status=PJ_SUCCESS; +#else + if (WaitForSingleObject(mutex->hMutex, INFINITE)==WAIT_OBJECT_0) + status = PJ_SUCCESS; + else + status = PJ_STATUS_FROM_OS(GetLastError()); + +#endif + PJ_LOG(6,(mutex->obj_name, + (status==PJ_SUCCESS ? "Mutex acquired by thread %s" : "FAILED by %s"), + pj_thread_this()->obj_name)); + +#if PJ_DEBUG + if (status == PJ_SUCCESS) { + mutex->owner = pj_thread_this(); + ++mutex->nesting_level; + } +#endif + + return status; +} + +/* + * pj_mutex_unlock() + */ +PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex) +{ + pj_status_t status; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(mutex, PJ_EINVAL); + +#if PJ_DEBUG + pj_assert(mutex->owner == pj_thread_this()); + if (--mutex->nesting_level == 0) { + mutex->owner = NULL; + } +#endif + + PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s", + pj_thread_this()->obj_name)); + +#if PJ_WIN32_WINNT >= 0x0400 + LeaveCriticalSection(&mutex->crit); + status=PJ_SUCCESS; +#else + status = ReleaseMutex(mutex->hMutex) ? PJ_SUCCESS : + PJ_STATUS_FROM_OS(GetLastError()); +#endif + return status; +} + +/* + * pj_mutex_trylock() + */ +PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex) +{ + pj_status_t status; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(mutex, PJ_EINVAL); + +#if PJ_WIN32_WINNT >= 0x0400 + status=TryEnterCriticalSection(&mutex->crit) ? PJ_SUCCESS : PJ_EUNKNOWN; +#else + status = WaitForSingleObject(mutex->hMutex, 0)==WAIT_OBJECT_0 ? + PJ_SUCCESS : PJ_ETIMEDOUT; +#endif + if (status==PJ_SUCCESS) { + PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s", + pj_thread_this()->obj_name)); + +#if PJ_DEBUG + mutex->owner = pj_thread_this(); + ++mutex->nesting_level; +#endif + } + return status; +} + +/* + * pj_mutex_destroy() + */ +PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(mutex, PJ_EINVAL); + + PJ_LOG(6,(mutex->obj_name, "Mutex destroyed")); + +#if PJ_WIN32_WINNT >= 0x0400 + DeleteCriticalSection(&mutex->crit); + return PJ_SUCCESS; +#else + return CloseHandle(mutex->hMutex) ? PJ_SUCCESS : + PJ_RETURN_OS_ERROR(GetLastError()); +#endif +} + +#if PJ_DEBUG +/* + * pj_mutex_is_locked() + */ +PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex) +{ + return mutex->owner == pj_thread_this(); +} +#endif + +/////////////////////////////////////////////////////////////////////////////// +/* + * pj_enter_critical_section() + */ +PJ_DEF(void) pj_enter_critical_section(void) +{ + pj_mutex_lock(&critical_section_mutex); +} + + +/* + * pj_leave_critical_section() + */ +PJ_DEF(void) pj_leave_critical_section(void) +{ + pj_mutex_unlock(&critical_section_mutex); +} + +/////////////////////////////////////////////////////////////////////////////// +#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 + +/* + * pj_sem_create() + */ +PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool, + const char *name, + unsigned initial, + unsigned max, + pj_sem_t **sem_ptr) +{ + pj_sem_t *sem; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(pool && sem_ptr, PJ_EINVAL); + + sem = pj_pool_alloc(pool, sizeof(*sem)); + sem->hSemaphore = CreateSemaphore(NULL, initial, max, NULL); + if (!sem->hSemaphore) + return PJ_RETURN_OS_ERROR(GetLastError()); + + /* Set name. */ + if (!name) { + name = "sem%p"; + } + if (strchr(name, '%')) { + pj_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem); + } else { + strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME); + sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; + } + + PJ_LOG(6, (sem->obj_name, "Semaphore created")); + + *sem_ptr = sem; + return PJ_SUCCESS; +} + +static pj_status_t pj_sem_wait_for(pj_sem_t *sem, unsigned timeout) +{ + DWORD result; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(sem, PJ_EINVAL); + + PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting", + pj_thread_this()->obj_name)); + + result = WaitForSingleObject(sem->hSemaphore, timeout); + if (result == WAIT_OBJECT_0) { + PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", + pj_thread_this()->obj_name)); + } else { + PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire", + pj_thread_this()->obj_name)); + } + + if (result==WAIT_OBJECT_0) + return PJ_SUCCESS; + else if (result==WAIT_TIMEOUT) + return PJ_ETIMEDOUT; + else + return PJ_RETURN_OS_ERROR(GetLastError()); +} + +/* + * pj_sem_wait() + */ +PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(sem, PJ_EINVAL); + + return pj_sem_wait_for(sem, INFINITE); +} + +/* + * pj_sem_trywait() + */ +PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(sem, PJ_EINVAL); + + return pj_sem_wait_for(sem, 0); +} + +/* + * pj_sem_post() + */ +PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(sem, PJ_EINVAL); + + PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s", + pj_thread_this()->obj_name)); + + if (ReleaseSemaphore(sem->hSemaphore, 1, NULL)) + return PJ_SUCCESS; + else + return PJ_RETURN_OS_ERROR(GetLastError()); +} + +/* + * pj_sem_destroy() + */ +PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(sem, PJ_EINVAL); + + PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s", + pj_thread_this()->obj_name)); + + if (CloseHandle(sem->hSemaphore)) + return PJ_SUCCESS; + else + return PJ_RETURN_OS_ERROR(GetLastError()); +} + +#endif /* PJ_HAS_SEMAPHORE */ +/////////////////////////////////////////////////////////////////////////////// + + +#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0 + +/* + * pj_event_create() + */ +PJ_DEF(pj_status_t) pj_event_create( pj_pool_t *pool, + const char *name, + pj_bool_t manual_reset, + pj_bool_t initial, + pj_event_t **event_ptr) +{ + pj_event_t *event; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(pool && event_ptr, PJ_EINVAL); + + event = pj_pool_alloc(pool, sizeof(*event)); + if (!event) + return PJ_ENOMEM; + + event->hEvent = CreateEvent(NULL, manual_reset?TRUE:FALSE, + initial?TRUE:FALSE, NULL); + + if (!event->hEvent) + return PJ_RETURN_OS_ERROR(GetLastError()); + + /* Set name. */ + if (!name) { + name = "evt%p"; + } + if (strchr(name, '%')) { + pj_snprintf(event->obj_name, PJ_MAX_OBJ_NAME, name, event); + } else { + strncpy(event->obj_name, name, PJ_MAX_OBJ_NAME); + event->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; + } + + PJ_LOG(6, (event->obj_name, "Event created")); + + *event_ptr = event; + return PJ_SUCCESS; +} + +static pj_status_t pj_event_wait_for(pj_event_t *event, unsigned timeout) +{ + DWORD result; + + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(event, PJ_EINVAL); + + PJ_LOG(6, (event->obj_name, "Event: thread %s is waiting", + pj_thread_this()->obj_name)); + + result = WaitForSingleObject(event->hEvent, timeout); + if (result == WAIT_OBJECT_0) { + PJ_LOG(6, (event->obj_name, "Event: thread %s is released", + pj_thread_this()->obj_name)); + } else { + PJ_LOG(6, (event->obj_name, "Event: thread %s FAILED to acquire", + pj_thread_this()->obj_name)); + } + + if (result==WAIT_OBJECT_0) + return PJ_SUCCESS; + else if (result==WAIT_TIMEOUT) + return PJ_ETIMEDOUT; + else + return PJ_RETURN_OS_ERROR(GetLastError()); +} + +/* + * pj_event_wait() + */ +PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event) +{ + PJ_ASSERT_RETURN(event, PJ_EINVAL); + + return pj_event_wait_for(event, INFINITE); +} + +/* + * pj_event_trywait() + */ +PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event) +{ + PJ_ASSERT_RETURN(event, PJ_EINVAL); + + return pj_event_wait_for(event, 0); +} + +/* + * pj_event_set() + */ +PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(event, PJ_EINVAL); + + PJ_LOG(6, (event->obj_name, "Setting event")); + + if (SetEvent(event->hEvent)) + return PJ_SUCCESS; + else + return PJ_RETURN_OS_ERROR(GetLastError()); +} + +/* + * pj_event_pulse() + */ +PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(event, PJ_EINVAL); + + PJ_LOG(6, (event->obj_name, "Pulsing event")); + + if (PulseEvent(event->hEvent)) + return PJ_SUCCESS; + else + return PJ_RETURN_OS_ERROR(GetLastError()); +} + +/* + * pj_event_reset() + */ +PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(event, PJ_EINVAL); + + PJ_LOG(6, (event->obj_name, "Event is reset")); + + if (ResetEvent(event->hEvent)) + return PJ_SUCCESS; + else + return PJ_RETURN_OS_ERROR(GetLastError()); +} + +/* + * pj_event_destroy() + */ +PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(event, PJ_EINVAL); + + PJ_LOG(6, (event->obj_name, "Event is destroying")); + + if (CloseHandle(event->hEvent)) + return PJ_SUCCESS; + else + return PJ_RETURN_OS_ERROR(GetLastError()); +} + +#endif /* PJ_HAS_EVENT_OBJ */ + +/////////////////////////////////////////////////////////////////////////////// +#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0 +/* + * Terminal color + */ + +static WORD pj_color_to_os_attr(pj_color_t color) +{ + WORD attr = 0; + + if (color & PJ_TERM_COLOR_R) + attr |= FOREGROUND_RED; + if (color & PJ_TERM_COLOR_G) + attr |= FOREGROUND_GREEN; + if (color & PJ_TERM_COLOR_B) + attr |= FOREGROUND_BLUE; + if (color & PJ_TERM_COLOR_BRIGHT) + attr |= FOREGROUND_INTENSITY; + + return attr; +} + +static pj_color_t os_attr_to_pj_color(WORD attr) +{ + int color = 0; + + if (attr & FOREGROUND_RED) + color |= PJ_TERM_COLOR_R; + if (attr & FOREGROUND_GREEN) + color |= PJ_TERM_COLOR_G; + if (attr & FOREGROUND_BLUE) + color |= PJ_TERM_COLOR_B; + if (attr & FOREGROUND_INTENSITY) + color |= PJ_TERM_COLOR_BRIGHT; + + return color; +} + + +/* + * pj_term_set_color() + */ +PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color) +{ + BOOL rc; + WORD attr = 0; + + PJ_CHECK_STACK(); + + attr = pj_color_to_os_attr(color); + rc = SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), attr); + return rc ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError()); +} + +/* + * pj_term_get_color() + * Get current terminal foreground color. + */ +PJ_DEF(pj_color_t) pj_term_get_color(void) +{ + CONSOLE_SCREEN_BUFFER_INFO info; + + PJ_CHECK_STACK(); + + GetConsoleScreenBufferInfo( GetStdHandle(STD_OUTPUT_HANDLE), &info); + return os_attr_to_pj_color(info.wAttributes); +} + +#endif /* PJ_TERM_HAS_COLOR */ diff --git a/pjlib/src/pj/os_error_linux_kernel.c b/pjlib/src/pj/os_error_linux_kernel.c index 4c83b491..7951c2db 100644 --- a/pjlib/src/pj/os_error_linux_kernel.c +++ b/pjlib/src/pj/os_error_linux_kernel.c @@ -1,73 +1,73 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/os_error_linux_kernel.c 2 10/29/05 11:51a Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pj/os_error_linux_kernel.c $ - * - * 2 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 1 10/19/05 1:48p Bennylp - * Created. - * - */ -#include -#include -#include -#include -#if defined(MODVERSIONS) -#include -#endif -#include -#include - -int kernel_errno; - -PJ_DEF(pj_status_t) pj_get_os_error(void) -{ - return errno; -} - -PJ_DEF(void) pj_set_os_error(pj_status_t code) -{ - errno = code; -} - -PJ_DEF(pj_status_t) pj_get_netos_error(void) -{ - return errno; -} - -PJ_DEF(void) pj_set_netos_error(pj_status_t code) -{ - errno = code; -} - -/* - * platform_strerror() - * - * Platform specific error message. This file is called by pj_strerror() - * in errno.c - */ -int platform_strerror( pj_os_err_type os_errcode, - char *buf, pj_size_t bufsize) -{ - char errmsg[32]; - int len; - - /* Handle EINVAL as special case so that it'll pass errno test. */ - if (os_errcode==EINVAL) - strcpy(errmsg, "Invalid value"); - else - sprintf(errmsg, "errno=%d", os_errcode); - - len = strlen(errmsg); - - if (len >= bufsize) - len = bufsize-1; - - pj_memcpy(buf, errmsg, len); - buf[len] = '\0'; - - return len; -} - - +/* $Header: /pjproject-0.3/pjlib/src/pj/os_error_linux_kernel.c 2 10/29/05 11:51a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pj/os_error_linux_kernel.c $ + * + * 2 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 1 10/19/05 1:48p Bennylp + * Created. + * + */ +#include +#include +#include +#include +#if defined(MODVERSIONS) +#include +#endif +#include +#include + +int kernel_errno; + +PJ_DEF(pj_status_t) pj_get_os_error(void) +{ + return errno; +} + +PJ_DEF(void) pj_set_os_error(pj_status_t code) +{ + errno = code; +} + +PJ_DEF(pj_status_t) pj_get_netos_error(void) +{ + return errno; +} + +PJ_DEF(void) pj_set_netos_error(pj_status_t code) +{ + errno = code; +} + +/* + * platform_strerror() + * + * Platform specific error message. This file is called by pj_strerror() + * in errno.c + */ +int platform_strerror( pj_os_err_type os_errcode, + char *buf, pj_size_t bufsize) +{ + char errmsg[32]; + int len; + + /* Handle EINVAL as special case so that it'll pass errno test. */ + if (os_errcode==EINVAL) + strcpy(errmsg, "Invalid value"); + else + sprintf(errmsg, "errno=%d", os_errcode); + + len = strlen(errmsg); + + if (len >= bufsize) + len = bufsize-1; + + pj_memcpy(buf, errmsg, len); + buf[len] = '\0'; + + return len; +} + + diff --git a/pjlib/src/pj/os_error_unix.c b/pjlib/src/pj/os_error_unix.c index f526c671..599ea57a 100644 --- a/pjlib/src/pj/os_error_unix.c +++ b/pjlib/src/pj/os_error_unix.c @@ -1,52 +1,52 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/os_error_unix.c 1 10/14/05 12:19a Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pj/os_error_unix.c $ - * - * 1 10/14/05 12:19a Bennylp - * Created. - * - */ -#include -#include -#include - -PJ_DEF(pj_status_t) pj_get_os_error(void) -{ - return PJ_STATUS_FROM_OS(errno); -} - -PJ_DEF(void) pj_set_os_error(pj_status_t code) -{ - errno = PJ_STATUS_TO_OS(code); -} - -PJ_DEF(pj_status_t) pj_get_netos_error(void) -{ - return PJ_STATUS_FROM_OS(errno); -} - -PJ_DEF(void) pj_set_netos_error(pj_status_t code) -{ - errno = PJ_STATUS_TO_OS(code); -} - -/* - * platform_strerror() - * - * Platform specific error message. This file is called by pj_strerror() - * in errno.c - */ -int platform_strerror( pj_os_err_type os_errcode, - char *buf, pj_size_t bufsize) -{ - const char *syserr = strerror(os_errcode); - pj_size_t len = syserr ? strlen(syserr) : 0; - - if (len >= bufsize) len = bufsize - 1; - if (len > 0) - pj_memcpy(buf, syserr, len); - buf[len] = '\0'; - return len; -} - - +/* $Header: /pjproject-0.3/pjlib/src/pj/os_error_unix.c 1 10/14/05 12:19a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pj/os_error_unix.c $ + * + * 1 10/14/05 12:19a Bennylp + * Created. + * + */ +#include +#include +#include + +PJ_DEF(pj_status_t) pj_get_os_error(void) +{ + return PJ_STATUS_FROM_OS(errno); +} + +PJ_DEF(void) pj_set_os_error(pj_status_t code) +{ + errno = PJ_STATUS_TO_OS(code); +} + +PJ_DEF(pj_status_t) pj_get_netos_error(void) +{ + return PJ_STATUS_FROM_OS(errno); +} + +PJ_DEF(void) pj_set_netos_error(pj_status_t code) +{ + errno = PJ_STATUS_TO_OS(code); +} + +/* + * platform_strerror() + * + * Platform specific error message. This file is called by pj_strerror() + * in errno.c + */ +int platform_strerror( pj_os_err_type os_errcode, + char *buf, pj_size_t bufsize) +{ + const char *syserr = strerror(os_errcode); + pj_size_t len = syserr ? strlen(syserr) : 0; + + if (len >= bufsize) len = bufsize - 1; + if (len > 0) + pj_memcpy(buf, syserr, len); + buf[len] = '\0'; + return len; +} + + diff --git a/pjlib/src/pj/os_error_win32.c b/pjlib/src/pj/os_error_win32.c index 19471fcf..d0fe2c76 100644 --- a/pjlib/src/pj/os_error_win32.c +++ b/pjlib/src/pj/os_error_win32.c @@ -1,161 +1,161 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/os_error_win32.c 3 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/os_error_win32.c $ - * - * 3 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 2 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#include -#include -#include -#include -#include -#include - - -#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0 -# include -#elif defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0 -# include -#endif - - -/* - * From Apache's APR: - */ -static const struct { - pj_os_err_type code; - const char *msg; -} gaErrorList[] = { - {WSAEINTR, "Interrupted system call"}, - {WSAEBADF, "Bad file number"}, - {WSAEACCES, "Permission denied"}, - {WSAEFAULT, "Bad address"}, - {WSAEINVAL, "Invalid argument"}, - {WSAEMFILE, "Too many open sockets"}, - {WSAEWOULDBLOCK, "Operation would block"}, - {WSAEINPROGRESS, "Operation now in progress"}, - {WSAEALREADY, "Operation already in progress"}, - {WSAENOTSOCK, "Socket operation on non-socket"}, - {WSAEDESTADDRREQ, "Destination address required"}, - {WSAEMSGSIZE, "Message too long"}, - {WSAEPROTOTYPE, "Protocol wrong type for socket"}, - {WSAENOPROTOOPT, "Bad protocol option"}, - {WSAEPROTONOSUPPORT, "Protocol not supported"}, - {WSAESOCKTNOSUPPORT, "Socket type not supported"}, - {WSAEOPNOTSUPP, "Operation not supported on socket"}, - {WSAEPFNOSUPPORT, "Protocol family not supported"}, - {WSAEAFNOSUPPORT, "Address family not supported"}, - {WSAEADDRINUSE, "Address already in use"}, - {WSAEADDRNOTAVAIL, "Can't assign requested address"}, - {WSAENETDOWN, "Network is down"}, - {WSAENETUNREACH, "Network is unreachable"}, - {WSAENETRESET, "Net connection reset"}, - {WSAECONNABORTED, "Software caused connection abort"}, - {WSAECONNRESET, "Connection reset by peer"}, - {WSAENOBUFS, "No buffer space available"}, - {WSAEISCONN, "Socket is already connected"}, - {WSAENOTCONN, "Socket is not connected"}, - {WSAESHUTDOWN, "Can't send after socket shutdown"}, - {WSAETOOMANYREFS, "Too many references, can't splice"}, - {WSAETIMEDOUT, "Connection timed out"}, - {WSAECONNREFUSED, "Connection refused"}, - {WSAELOOP, "Too many levels of symbolic links"}, - {WSAENAMETOOLONG, "File name too long"}, - {WSAEHOSTDOWN, "Host is down"}, - {WSAEHOSTUNREACH, "No route to host"}, - {WSAENOTEMPTY, "Directory not empty"}, - {WSAEPROCLIM, "Too many processes"}, - {WSAEUSERS, "Too many users"}, - {WSAEDQUOT, "Disc quota exceeded"}, - {WSAESTALE, "Stale NFS file handle"}, - {WSAEREMOTE, "Too many levels of remote in path"}, - {WSASYSNOTREADY, "Network system is unavailable"}, - {WSAVERNOTSUPPORTED, "Winsock version out of range"}, - {WSANOTINITIALISED, "WSAStartup not yet called"}, - {WSAEDISCON, "Graceful shutdown in progress"}, - {WSAHOST_NOT_FOUND, "Host not found"}, - {WSANO_DATA, "No host data of that type was found"}, - {0, NULL} -}; - - -PJ_DEF(pj_status_t) pj_get_os_error(void) -{ - return PJ_STATUS_FROM_OS(GetLastError()); -} - -PJ_DEF(void) pj_set_os_error(pj_status_t code) -{ - SetLastError(PJ_STATUS_TO_OS(code)); -} - -PJ_DEF(pj_status_t) pj_get_netos_error(void) -{ - return PJ_STATUS_FROM_OS(WSAGetLastError()); -} - -PJ_DEF(void) pj_set_netos_error(pj_status_t code) -{ - WSASetLastError(PJ_STATUS_TO_OS(code)); -} - -/* - * platform_strerror() - * - * Platform specific error message. This file is called by pj_strerror() - * in errno.c - */ -int platform_strerror( pj_os_err_type os_errcode, - char *buf, pj_size_t bufsize) -{ - int len; - - pj_assert(buf != NULL); - pj_assert(bufsize >= 0); - - /* - * MUST NOT check stack here. - * This function might be called from PJ_CHECK_STACK() itself! - //PJ_CHECK_STACK(); - */ - - len = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM - | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - os_errcode, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)buf, - (DWORD)bufsize, - NULL); - - if (!len) { - int i; - for (i = 0; gaErrorList[i].msg; ++i) { - if (gaErrorList[i].code == os_errcode) { - len = strlen(gaErrorList[i].msg); - if ((pj_size_t)len >= bufsize) { - len = bufsize-1; - } - pj_memcpy(buf, gaErrorList[i].msg, len); - buf[len] = '\0'; - break; - } - } - } - - if (!len) { - len = snprintf( buf, bufsize, "Unknown native error %u", (unsigned)os_errcode); - buf[len] = '\0'; - } - - return len; -} - +/* $Header: /pjproject-0.3/pjlib/src/pj/os_error_win32.c 3 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/os_error_win32.c $ + * + * 3 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 2 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 1 9/17/05 10:36a Bennylp + * Created. + * + */ +#include +#include +#include +#include +#include +#include + + +#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0 +# include +#elif defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0 +# include +#endif + + +/* + * From Apache's APR: + */ +static const struct { + pj_os_err_type code; + const char *msg; +} gaErrorList[] = { + {WSAEINTR, "Interrupted system call"}, + {WSAEBADF, "Bad file number"}, + {WSAEACCES, "Permission denied"}, + {WSAEFAULT, "Bad address"}, + {WSAEINVAL, "Invalid argument"}, + {WSAEMFILE, "Too many open sockets"}, + {WSAEWOULDBLOCK, "Operation would block"}, + {WSAEINPROGRESS, "Operation now in progress"}, + {WSAEALREADY, "Operation already in progress"}, + {WSAENOTSOCK, "Socket operation on non-socket"}, + {WSAEDESTADDRREQ, "Destination address required"}, + {WSAEMSGSIZE, "Message too long"}, + {WSAEPROTOTYPE, "Protocol wrong type for socket"}, + {WSAENOPROTOOPT, "Bad protocol option"}, + {WSAEPROTONOSUPPORT, "Protocol not supported"}, + {WSAESOCKTNOSUPPORT, "Socket type not supported"}, + {WSAEOPNOTSUPP, "Operation not supported on socket"}, + {WSAEPFNOSUPPORT, "Protocol family not supported"}, + {WSAEAFNOSUPPORT, "Address family not supported"}, + {WSAEADDRINUSE, "Address already in use"}, + {WSAEADDRNOTAVAIL, "Can't assign requested address"}, + {WSAENETDOWN, "Network is down"}, + {WSAENETUNREACH, "Network is unreachable"}, + {WSAENETRESET, "Net connection reset"}, + {WSAECONNABORTED, "Software caused connection abort"}, + {WSAECONNRESET, "Connection reset by peer"}, + {WSAENOBUFS, "No buffer space available"}, + {WSAEISCONN, "Socket is already connected"}, + {WSAENOTCONN, "Socket is not connected"}, + {WSAESHUTDOWN, "Can't send after socket shutdown"}, + {WSAETOOMANYREFS, "Too many references, can't splice"}, + {WSAETIMEDOUT, "Connection timed out"}, + {WSAECONNREFUSED, "Connection refused"}, + {WSAELOOP, "Too many levels of symbolic links"}, + {WSAENAMETOOLONG, "File name too long"}, + {WSAEHOSTDOWN, "Host is down"}, + {WSAEHOSTUNREACH, "No route to host"}, + {WSAENOTEMPTY, "Directory not empty"}, + {WSAEPROCLIM, "Too many processes"}, + {WSAEUSERS, "Too many users"}, + {WSAEDQUOT, "Disc quota exceeded"}, + {WSAESTALE, "Stale NFS file handle"}, + {WSAEREMOTE, "Too many levels of remote in path"}, + {WSASYSNOTREADY, "Network system is unavailable"}, + {WSAVERNOTSUPPORTED, "Winsock version out of range"}, + {WSANOTINITIALISED, "WSAStartup not yet called"}, + {WSAEDISCON, "Graceful shutdown in progress"}, + {WSAHOST_NOT_FOUND, "Host not found"}, + {WSANO_DATA, "No host data of that type was found"}, + {0, NULL} +}; + + +PJ_DEF(pj_status_t) pj_get_os_error(void) +{ + return PJ_STATUS_FROM_OS(GetLastError()); +} + +PJ_DEF(void) pj_set_os_error(pj_status_t code) +{ + SetLastError(PJ_STATUS_TO_OS(code)); +} + +PJ_DEF(pj_status_t) pj_get_netos_error(void) +{ + return PJ_STATUS_FROM_OS(WSAGetLastError()); +} + +PJ_DEF(void) pj_set_netos_error(pj_status_t code) +{ + WSASetLastError(PJ_STATUS_TO_OS(code)); +} + +/* + * platform_strerror() + * + * Platform specific error message. This file is called by pj_strerror() + * in errno.c + */ +int platform_strerror( pj_os_err_type os_errcode, + char *buf, pj_size_t bufsize) +{ + int len; + + pj_assert(buf != NULL); + pj_assert(bufsize >= 0); + + /* + * MUST NOT check stack here. + * This function might be called from PJ_CHECK_STACK() itself! + //PJ_CHECK_STACK(); + */ + + len = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + os_errcode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)buf, + (DWORD)bufsize, + NULL); + + if (!len) { + int i; + for (i = 0; gaErrorList[i].msg; ++i) { + if (gaErrorList[i].code == os_errcode) { + len = strlen(gaErrorList[i].msg); + if ((pj_size_t)len >= bufsize) { + len = bufsize-1; + } + pj_memcpy(buf, gaErrorList[i].msg, len); + buf[len] = '\0'; + break; + } + } + } + + if (!len) { + len = snprintf( buf, bufsize, "Unknown native error %u", (unsigned)os_errcode); + buf[len] = '\0'; + } + + return len; +} + diff --git a/pjlib/src/pj/os_time_ansi.c b/pjlib/src/pj/os_time_ansi.c index 906b21d6..0d6d9d7e 100644 --- a/pjlib/src/pj/os_time_ansi.c +++ b/pjlib/src/pj/os_time_ansi.c @@ -1,65 +1,65 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/os_time_ansi.c 2 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/os_time_ansi.c $ - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 9/17/05 10:36a Bennylp - * Created. - * - */ -#include -#include - -/////////////////////////////////////////////////////////////////////////////// - -PJ_DEF(pj_status_t) pj_gettimeofday(pj_time_val *tv) -{ - struct timeb tb; - - PJ_CHECK_STACK(); - - ftime(&tb); - tv->sec = tb.time; - tv->msec = tb.millitm; - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt) -{ - struct tm *local_time; - - PJ_CHECK_STACK(); - - local_time = localtime((time_t*)&tv->sec); - - pt->year = local_time->tm_year+1900; - pt->mon = local_time->tm_mon; - pt->day = local_time->tm_mday; - pt->hour = local_time->tm_hour; - pt->min = local_time->tm_min; - pt->sec = local_time->tm_sec; - pt->wday = local_time->tm_wday; - pt->yday = local_time->tm_yday; - pt->msec = tv->msec; - - return PJ_SUCCESS; -} - -/** - * Encode parsed time to time value. - */ -PJ_DEF(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv); - -/** - * Convert local time to GMT. - */ -PJ_DEF(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv); - -/** - * Convert GMT to local time. - */ -PJ_DEF(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv); - - +/* $Header: /pjproject-0.3/pjlib/src/pj/os_time_ansi.c 2 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/os_time_ansi.c $ + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 9/17/05 10:36a Bennylp + * Created. + * + */ +#include +#include + +/////////////////////////////////////////////////////////////////////////////// + +PJ_DEF(pj_status_t) pj_gettimeofday(pj_time_val *tv) +{ + struct timeb tb; + + PJ_CHECK_STACK(); + + ftime(&tb); + tv->sec = tb.time; + tv->msec = tb.millitm; + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt) +{ + struct tm *local_time; + + PJ_CHECK_STACK(); + + local_time = localtime((time_t*)&tv->sec); + + pt->year = local_time->tm_year+1900; + pt->mon = local_time->tm_mon; + pt->day = local_time->tm_mday; + pt->hour = local_time->tm_hour; + pt->min = local_time->tm_min; + pt->sec = local_time->tm_sec; + pt->wday = local_time->tm_wday; + pt->yday = local_time->tm_yday; + pt->msec = tv->msec; + + return PJ_SUCCESS; +} + +/** + * Encode parsed time to time value. + */ +PJ_DEF(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv); + +/** + * Convert local time to GMT. + */ +PJ_DEF(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv); + +/** + * Convert GMT to local time. + */ +PJ_DEF(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv); + + diff --git a/pjlib/src/pj/os_time_linux_kernel.c b/pjlib/src/pj/os_time_linux_kernel.c index 4d5f4cb4..5ca1f4ed 100644 --- a/pjlib/src/pj/os_time_linux_kernel.c +++ b/pjlib/src/pj/os_time_linux_kernel.c @@ -1,58 +1,58 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/os_time_linux_kernel.c 2 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/os_time_linux_kernel.c $ - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 9/22/05 10:39a Bennylp - * Created. - * - */ -#include -#include - -/////////////////////////////////////////////////////////////////////////////// - -PJ_DEF(pj_status_t) pj_gettimeofday(pj_time_val *tv) -{ - struct timeval tval; - - do_gettimeofday(&tval); - tv->sec = tval.tv_sec; - tv->msec = tval.tv_usec / 1000; - - return 0; -} - -PJ_DEF(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt) -{ - pt->year = 2005; - pt->mon = 8; - pt->day = 20; - pt->hour = 16; - pt->min = 30; - pt->sec = 30; - pt->wday = 3; - pt->yday = 200; - pt->msec = 777; - - return -1; -} - -/** - * Encode parsed time to time value. - */ -PJ_DEF(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv); - -/** - * Convert local time to GMT. - */ -PJ_DEF(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv); - -/** - * Convert GMT to local time. - */ -PJ_DEF(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv); - - +/* $Header: /pjproject-0.3/pjlib/src/pj/os_time_linux_kernel.c 2 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/os_time_linux_kernel.c $ + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 9/22/05 10:39a Bennylp + * Created. + * + */ +#include +#include + +/////////////////////////////////////////////////////////////////////////////// + +PJ_DEF(pj_status_t) pj_gettimeofday(pj_time_val *tv) +{ + struct timeval tval; + + do_gettimeofday(&tval); + tv->sec = tval.tv_sec; + tv->msec = tval.tv_usec / 1000; + + return 0; +} + +PJ_DEF(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt) +{ + pt->year = 2005; + pt->mon = 8; + pt->day = 20; + pt->hour = 16; + pt->min = 30; + pt->sec = 30; + pt->wday = 3; + pt->yday = 200; + pt->msec = 777; + + return -1; +} + +/** + * Encode parsed time to time value. + */ +PJ_DEF(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv); + +/** + * Convert local time to GMT. + */ +PJ_DEF(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv); + +/** + * Convert GMT to local time. + */ +PJ_DEF(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv); + + diff --git a/pjlib/src/pj/os_timestamp_common.c b/pjlib/src/pj/os_timestamp_common.c index 630ffb27..3a170a33 100644 --- a/pjlib/src/pj/os_timestamp_common.c +++ b/pjlib/src/pj/os_timestamp_common.c @@ -1,129 +1,129 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/os_timestamp_common.c 2 10/14/05 12:26a Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pj/os_timestamp_common.c $ - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 10/09/05 2:56p Bennylp - * Created. - * - */ -#include -#include - -#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0 - -#define U32MAX (0xFFFFFFFFUL) -#define NANOSEC (1000000000UL) -#define USEC (1000000UL) -#define MSEC (1000) - -static pj_highprec_t get_elapsed( const pj_timestamp *start, - const pj_timestamp *stop ) -{ - pj_highprec_t elapsed_hi, elapsed_lo; - - elapsed_hi = stop->u32.hi - start->u32.hi; - elapsed_lo = stop->u32.lo - start->u32.lo; - - /* elapsed_hi = elapsed_hi * U32MAX */ - pj_highprec_mul(elapsed_hi, U32MAX); - - return elapsed_hi + elapsed_lo; -} - -static pj_highprec_t elapsed_usec( const pj_timestamp *start, - const pj_timestamp *stop ) -{ - pj_timestamp ts_freq; - pj_highprec_t freq, elapsed; - - if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS) - return 0; - - /* Convert frequency timestamp */ - freq = ts_freq.u32.hi; - pj_highprec_mul(freq, U32MAX); - freq += ts_freq.u32.lo; - - /* Avoid division by zero. */ - if (freq == 0) freq = 1; - - /* Get elapsed time in cycles. */ - elapsed = get_elapsed(start, stop); - - /* usec = elapsed * USEC / freq */ - pj_highprec_mul(elapsed, USEC); - pj_highprec_div(elapsed, freq); - - return elapsed; -} - -PJ_DEF(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start, - const pj_timestamp *stop ) -{ - pj_timestamp ts_freq; - pj_highprec_t freq, elapsed; - - if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS) - return 0; - - /* Convert frequency timestamp */ - freq = ts_freq.u32.hi; - pj_highprec_mul(freq, U32MAX); - freq += ts_freq.u32.lo; - - /* Avoid division by zero. */ - if (freq == 0) freq = 1; - - /* Get elapsed time in cycles. */ - elapsed = get_elapsed(start, stop); - - /* usec = elapsed * USEC / freq */ - pj_highprec_mul(elapsed, NANOSEC); - pj_highprec_div(elapsed, freq); - - return (pj_uint32_t)elapsed; -} - -PJ_DEF(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start, - const pj_timestamp *stop ) -{ - return (pj_uint32_t)elapsed_usec(start, stop); -} - -PJ_DEF(pj_time_val) pj_elapsed_time( const pj_timestamp *start, - const pj_timestamp *stop ) -{ - pj_highprec_t elapsed = elapsed_usec(start, stop); - pj_time_val tv_elapsed; - - if (PJ_HIGHPREC_VALUE_IS_ZERO(elapsed)) { - tv_elapsed.sec = tv_elapsed.msec = 0; - return tv_elapsed; - } else { - pj_highprec_t sec, msec; - - sec = elapsed; - pj_highprec_div(sec, USEC); - tv_elapsed.sec = (long)sec; - - msec = elapsed; - pj_highprec_mod(msec, USEC); - pj_highprec_div(msec, 1000); - tv_elapsed.msec = (long)msec; - - return tv_elapsed; - } -} - -PJ_DEF(pj_uint32_t) pj_elapsed_cycle( const pj_timestamp *start, - const pj_timestamp *stop ) -{ - return stop->u32.lo - start->u32.lo; -} - -#endif /* PJ_HAS_HIGH_RES_TIMER */ - +/* $Header: /pjproject-0.3/pjlib/src/pj/os_timestamp_common.c 2 10/14/05 12:26a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pj/os_timestamp_common.c $ + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 10/09/05 2:56p Bennylp + * Created. + * + */ +#include +#include + +#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0 + +#define U32MAX (0xFFFFFFFFUL) +#define NANOSEC (1000000000UL) +#define USEC (1000000UL) +#define MSEC (1000) + +static pj_highprec_t get_elapsed( const pj_timestamp *start, + const pj_timestamp *stop ) +{ + pj_highprec_t elapsed_hi, elapsed_lo; + + elapsed_hi = stop->u32.hi - start->u32.hi; + elapsed_lo = stop->u32.lo - start->u32.lo; + + /* elapsed_hi = elapsed_hi * U32MAX */ + pj_highprec_mul(elapsed_hi, U32MAX); + + return elapsed_hi + elapsed_lo; +} + +static pj_highprec_t elapsed_usec( const pj_timestamp *start, + const pj_timestamp *stop ) +{ + pj_timestamp ts_freq; + pj_highprec_t freq, elapsed; + + if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS) + return 0; + + /* Convert frequency timestamp */ + freq = ts_freq.u32.hi; + pj_highprec_mul(freq, U32MAX); + freq += ts_freq.u32.lo; + + /* Avoid division by zero. */ + if (freq == 0) freq = 1; + + /* Get elapsed time in cycles. */ + elapsed = get_elapsed(start, stop); + + /* usec = elapsed * USEC / freq */ + pj_highprec_mul(elapsed, USEC); + pj_highprec_div(elapsed, freq); + + return elapsed; +} + +PJ_DEF(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start, + const pj_timestamp *stop ) +{ + pj_timestamp ts_freq; + pj_highprec_t freq, elapsed; + + if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS) + return 0; + + /* Convert frequency timestamp */ + freq = ts_freq.u32.hi; + pj_highprec_mul(freq, U32MAX); + freq += ts_freq.u32.lo; + + /* Avoid division by zero. */ + if (freq == 0) freq = 1; + + /* Get elapsed time in cycles. */ + elapsed = get_elapsed(start, stop); + + /* usec = elapsed * USEC / freq */ + pj_highprec_mul(elapsed, NANOSEC); + pj_highprec_div(elapsed, freq); + + return (pj_uint32_t)elapsed; +} + +PJ_DEF(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start, + const pj_timestamp *stop ) +{ + return (pj_uint32_t)elapsed_usec(start, stop); +} + +PJ_DEF(pj_time_val) pj_elapsed_time( const pj_timestamp *start, + const pj_timestamp *stop ) +{ + pj_highprec_t elapsed = elapsed_usec(start, stop); + pj_time_val tv_elapsed; + + if (PJ_HIGHPREC_VALUE_IS_ZERO(elapsed)) { + tv_elapsed.sec = tv_elapsed.msec = 0; + return tv_elapsed; + } else { + pj_highprec_t sec, msec; + + sec = elapsed; + pj_highprec_div(sec, USEC); + tv_elapsed.sec = (long)sec; + + msec = elapsed; + pj_highprec_mod(msec, USEC); + pj_highprec_div(msec, 1000); + tv_elapsed.msec = (long)msec; + + return tv_elapsed; + } +} + +PJ_DEF(pj_uint32_t) pj_elapsed_cycle( const pj_timestamp *start, + const pj_timestamp *stop ) +{ + return stop->u32.lo - start->u32.lo; +} + +#endif /* PJ_HAS_HIGH_RES_TIMER */ + diff --git a/pjlib/src/pj/os_timestamp_linux.c b/pjlib/src/pj/os_timestamp_linux.c index 52639dcd..ee94e6e8 100644 --- a/pjlib/src/pj/os_timestamp_linux.c +++ b/pjlib/src/pj/os_timestamp_linux.c @@ -1,137 +1,137 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/os_timestamp_linux.c 4 10/29/05 10:27p Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/os_timestamp_linux.c $ - * - * 4 10/29/05 10:27p Bennylp - * Fixed misc warnings. - * - * 3 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 2 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 1 9/18/05 9:25p Bennylp - * Created. - * - */ -#include -#include -#include -#include -#include -#include - -#if defined(PJ_HAS_PENTIUM) && PJ_HAS_PENTIUM!=0 -static int machine_speed_mhz; -static pj_timestamp machine_speed; - -static __inline__ unsigned long long int rdtsc() -{ - unsigned long long int x; - __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); - return x; -} - -/* Determine machine's CPU MHz to get the counter's frequency. - */ -static int get_machine_speed_mhz() -{ - FILE *strm; - char buf[512]; - int len; - char *pos, *end; - - PJ_CHECK_STACK(); - - /* Open /proc/cpuinfo and read the file */ - strm = fopen("/proc/cpuinfo", "r"); - if (!strm) - return -1; - len = fread(buf, 1, sizeof(buf), strm); - fclose(strm); - if (len < 1) { - return -1; - } - buf[len] = '\0'; - - /* Locate the MHz digit. */ - pos = strstr(buf, "cpu MHz"); - if (!pos) - return -1; - pos = strchr(pos, ':'); - if (!pos) - return -1; - end = (pos += 2); - while (isdigit(*end)) ++end; - *end = '\0'; - - /* Return the Mhz part, and give it a +1. */ - return atoi(pos)+1; -} - -PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts) -{ - if (machine_speed_mhz == 0) { - machine_speed_mhz = get_machine_speed_mhz(); - if (machine_speed_mhz > 0) { - machine_speed.u64 = machine_speed_mhz * 1000000.0; - } - } - - if (machine_speed_mhz == -1) { - ts->u64 = 0; - return -1; - } - ts->u64 = rdtsc(); - return 0; -} - -PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq) -{ - if (machine_speed_mhz == 0) { - machine_speed_mhz = get_machine_speed_mhz(); - if (machine_speed_mhz > 0) { - machine_speed.u64 = machine_speed_mhz * 1000000.0; - } - } - - if (machine_speed_mhz == -1) { - freq->u64 = 1; /* return 1 to prevent division by zero in apps. */ - return -1; - } - - freq->u64 = machine_speed.u64; - return 0; -} - -#else -#include -#include - -#define USEC_PER_SEC 1000000 - -PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts) -{ - struct timeval tv; - - if (gettimeofday(&tv, NULL) != 0) { - return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); - } - - ts->u64 = tv.tv_sec; - ts->u64 *= USEC_PER_SEC; - ts->u64 += tv.tv_usec; - - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq) -{ - freq->u32.hi = 0; - freq->u32.lo = USEC_PER_SEC; - - return PJ_SUCCESS; -} - -#endif - +/* $Header: /pjproject-0.3/pjlib/src/pj/os_timestamp_linux.c 4 10/29/05 10:27p Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/os_timestamp_linux.c $ + * + * 4 10/29/05 10:27p Bennylp + * Fixed misc warnings. + * + * 3 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 2 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 1 9/18/05 9:25p Bennylp + * Created. + * + */ +#include +#include +#include +#include +#include +#include + +#if defined(PJ_HAS_PENTIUM) && PJ_HAS_PENTIUM!=0 +static int machine_speed_mhz; +static pj_timestamp machine_speed; + +static __inline__ unsigned long long int rdtsc() +{ + unsigned long long int x; + __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); + return x; +} + +/* Determine machine's CPU MHz to get the counter's frequency. + */ +static int get_machine_speed_mhz() +{ + FILE *strm; + char buf[512]; + int len; + char *pos, *end; + + PJ_CHECK_STACK(); + + /* Open /proc/cpuinfo and read the file */ + strm = fopen("/proc/cpuinfo", "r"); + if (!strm) + return -1; + len = fread(buf, 1, sizeof(buf), strm); + fclose(strm); + if (len < 1) { + return -1; + } + buf[len] = '\0'; + + /* Locate the MHz digit. */ + pos = strstr(buf, "cpu MHz"); + if (!pos) + return -1; + pos = strchr(pos, ':'); + if (!pos) + return -1; + end = (pos += 2); + while (isdigit(*end)) ++end; + *end = '\0'; + + /* Return the Mhz part, and give it a +1. */ + return atoi(pos)+1; +} + +PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts) +{ + if (machine_speed_mhz == 0) { + machine_speed_mhz = get_machine_speed_mhz(); + if (machine_speed_mhz > 0) { + machine_speed.u64 = machine_speed_mhz * 1000000.0; + } + } + + if (machine_speed_mhz == -1) { + ts->u64 = 0; + return -1; + } + ts->u64 = rdtsc(); + return 0; +} + +PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq) +{ + if (machine_speed_mhz == 0) { + machine_speed_mhz = get_machine_speed_mhz(); + if (machine_speed_mhz > 0) { + machine_speed.u64 = machine_speed_mhz * 1000000.0; + } + } + + if (machine_speed_mhz == -1) { + freq->u64 = 1; /* return 1 to prevent division by zero in apps. */ + return -1; + } + + freq->u64 = machine_speed.u64; + return 0; +} + +#else +#include +#include + +#define USEC_PER_SEC 1000000 + +PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts) +{ + struct timeval tv; + + if (gettimeofday(&tv, NULL) != 0) { + return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); + } + + ts->u64 = tv.tv_sec; + ts->u64 *= USEC_PER_SEC; + ts->u64 += tv.tv_usec; + + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq) +{ + freq->u32.hi = 0; + freq->u32.lo = USEC_PER_SEC; + + return PJ_SUCCESS; +} + +#endif + diff --git a/pjlib/src/pj/os_timestamp_linux_kernel.c b/pjlib/src/pj/os_timestamp_linux_kernel.c index 8895cf9d..a5a538ef 100644 --- a/pjlib/src/pj/os_timestamp_linux_kernel.c +++ b/pjlib/src/pj/os_timestamp_linux_kernel.c @@ -1,70 +1,70 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/os_timestamp_linux_kernel.c 2 10/29/05 11:51a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/os_timestamp_linux_kernel.c $ - * - * 2 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 1 9/22/05 10:39a Bennylp - * Created. - * - */ -#include -#include - -#if 0 -PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts) -{ - ts->u32.hi = 0; - ts->u32.lo = jiffies; - return 0; -} - -PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq) -{ - freq->u32.hi = 0; - freq->u32.lo = HZ; - return 0; -} -#elif 0 -PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts) -{ - struct timespec tv; - - tv = CURRENT_TIME; - - ts->u64 = tv.tv_sec; - ts->u64 *= NSEC_PER_SEC; - ts->u64 += tv.tv_nsec; - - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq) -{ - freq->u32.hi = 0; - freq->u32.lo = NSEC_PER_SEC; - return 0; -} -#else -PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts) -{ - struct timeval tv; - - do_gettimeofday(&tv); - - ts->u64 = tv.tv_sec; - ts->u64 *= USEC_PER_SEC; - ts->u64 += tv.tv_usec; - - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq) -{ - freq->u32.hi = 0; - freq->u32.lo = USEC_PER_SEC; - return 0; -} - -#endif - +/* $Header: /pjproject-0.3/pjlib/src/pj/os_timestamp_linux_kernel.c 2 10/29/05 11:51a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/os_timestamp_linux_kernel.c $ + * + * 2 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 1 9/22/05 10:39a Bennylp + * Created. + * + */ +#include +#include + +#if 0 +PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts) +{ + ts->u32.hi = 0; + ts->u32.lo = jiffies; + return 0; +} + +PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq) +{ + freq->u32.hi = 0; + freq->u32.lo = HZ; + return 0; +} +#elif 0 +PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts) +{ + struct timespec tv; + + tv = CURRENT_TIME; + + ts->u64 = tv.tv_sec; + ts->u64 *= NSEC_PER_SEC; + ts->u64 += tv.tv_nsec; + + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq) +{ + freq->u32.hi = 0; + freq->u32.lo = NSEC_PER_SEC; + return 0; +} +#else +PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts) +{ + struct timeval tv; + + do_gettimeofday(&tv); + + ts->u64 = tv.tv_sec; + ts->u64 *= USEC_PER_SEC; + ts->u64 += tv.tv_usec; + + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq) +{ + freq->u32.hi = 0; + freq->u32.lo = USEC_PER_SEC; + return 0; +} + +#endif + diff --git a/pjlib/src/pj/os_timestamp_win32.c b/pjlib/src/pj/os_timestamp_win32.c index 787c4bfc..924bfc6f 100644 --- a/pjlib/src/pj/os_timestamp_win32.c +++ b/pjlib/src/pj/os_timestamp_win32.c @@ -1,38 +1,38 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/os_timestamp_win32.c 2 10/14/05 12:26a Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pj/os_timestamp_win32.c $ - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 9/18/05 8:15p Bennylp - * Created. - * - */ -#include -#include -#include - -PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts) -{ - LARGE_INTEGER val; - - if (!QueryPerformanceCounter(&val)) - return PJ_RETURN_OS_ERROR(GetLastError()); - - ts->u64 = val.QuadPart; - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq) -{ - LARGE_INTEGER val; - - if (!QueryPerformanceFrequency(&val)) - return PJ_RETURN_OS_ERROR(GetLastError()); - - freq->u64 = val.QuadPart; - return PJ_SUCCESS; -} - +/* $Header: /pjproject-0.3/pjlib/src/pj/os_timestamp_win32.c 2 10/14/05 12:26a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pj/os_timestamp_win32.c $ + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 9/18/05 8:15p Bennylp + * Created. + * + */ +#include +#include +#include + +PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts) +{ + LARGE_INTEGER val; + + if (!QueryPerformanceCounter(&val)) + return PJ_RETURN_OS_ERROR(GetLastError()); + + ts->u64 = val.QuadPart; + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq) +{ + LARGE_INTEGER val; + + if (!QueryPerformanceFrequency(&val)) + return PJ_RETURN_OS_ERROR(GetLastError()); + + freq->u64 = val.QuadPart; + return PJ_SUCCESS; +} + diff --git a/pjlib/src/pj/pool.c b/pjlib/src/pj/pool.c index 3bf195b0..4ad6280c 100644 --- a/pjlib/src/pj/pool.c +++ b/pjlib/src/pj/pool.c @@ -1,265 +1,265 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/pool.c 8 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/pool.c $ - * - * 8 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 7 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include -#include -#include -#include - -/* Include inline definitions when inlining is disabled. */ -#if !PJ_FUNCTIONS_ARE_INLINED -# include -#endif - -#define LOG(expr) PJ_LOG(5,expr) - -int PJ_NO_MEMORY_EXCEPTION; - -/* - * Create new block. - * Create a new big chunk of memory block, from which user allocation will be - * taken from. - */ -static pj_pool_block *pj_pool_create_block( pj_pool_t *pool, pj_size_t size) -{ - pj_pool_block *block; - - PJ_CHECK_STACK(); - pj_assert(size >= sizeof(pj_pool_block)); - - LOG((pool->obj_name, "create_block(sz=%u), cur.cap=%u, cur.used=%u", - size, pool->capacity, pool->used_size)); - - /* Request memory from allocator. */ - block = (pj_pool_block*) - (*pool->factory->policy.block_alloc)(pool->factory, size); - if (block == NULL) { - (*pool->callback)(pool, size); - return NULL; - } - - /* Add capacity. */ - pool->capacity += size; - pool->used_size += sizeof(pj_pool_block); - - /* Set block attribytes. */ - block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block); - block->end = ((unsigned char*)block) + size; - - /* Insert in the front of the list. */ - pj_list_insert_after(&pool->block_list, block); - - LOG((pool->obj_name," block created, buffer=%p-%p",block->buf, block->end)); - - return block; -} - -/* - * Allocate memory chunk for user from available blocks. - * This will iterate through block list to find space to allocate the chunk. - * If no space is available in all the blocks, a new block might be created - * (depending on whether the pool is allowed to resize). - */ -PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size) -{ - pj_pool_block *block = pool->block_list.next; - void *p; - unsigned block_size; - - PJ_CHECK_STACK(); - - while (block != &pool->block_list) { - p = pj_pool_alloc_from_block(pool, block, size); - if (p != NULL) - return p; - block = block->next; - } - /* No available space in all blocks. */ - - /* If pool is configured NOT to expand, return error. */ - if (pool->increment_size == 0) { - LOG((pool->obj_name, "Can't expand pool to allocate %u bytes " - "(used=%u, cap=%u)", - size, pool->used_size, pool->capacity)); - (*pool->callback)(pool, size); - return NULL; - } - - /* If pool is configured to expand, but the increment size - * is less than the required size, expand the pool by multiple - * increment size - */ - if (pool->increment_size < size + sizeof(pj_pool_block)) { - unsigned count; - count = (size + pool->increment_size + sizeof(pj_pool_block)) / - pool->increment_size; - block_size = count * pool->increment_size; - - } else { - block_size = pool->increment_size; - } - - LOG((pool->obj_name, - "%u bytes requested, resizing pool by %u bytes (used=%u, cap=%u)", - size, block_size, pool->used_size, pool->capacity)); - - block = pj_pool_create_block(pool, block_size); - if (!block) - return NULL; - - p = pj_pool_alloc_from_block(pool, block, size); - pj_assert(p != NULL); -#if PJ_DEBUG - if (p == NULL) { - p = p; - } -#endif - return p; -} - -/* - * Internal function to initialize pool. - */ -PJ_DEF(void) pj_pool_init_int( pj_pool_t *pool, - const char *name, - pj_size_t increment_size, - pj_pool_callback *callback) -{ - pj_pool_block *block; - - PJ_CHECK_STACK(); - - pool->increment_size = increment_size; - pool->callback = callback; - pool->used_size = sizeof(*pool); - block = pool->block_list.next; - while (block != &pool->block_list) { - pool->used_size += sizeof(pj_pool_block); - block = block->next; - } - - if (name) { - if (strchr(name, '%') != NULL) { - sprintf(pool->obj_name, name, pool); - } else { - strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME); - } - } else { - pool->obj_name[0] = '\0'; - } -} - -/* - * Create new memory pool. - */ -PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name, - pj_size_t initial_size, - pj_size_t increment_size, - pj_pool_callback *callback) -{ - pj_pool_t *pool; - pj_pool_block *block; - unsigned char *buffer; - - PJ_CHECK_STACK(); - - buffer = (*f->policy.block_alloc)(f, initial_size); - if (!buffer) - return NULL; - - /* Set pool administrative data. */ - pool = (pj_pool_t*)buffer; - pj_memset(pool, 0, sizeof(*pool)); - - pj_list_init(&pool->block_list); - pool->factory = f; - - /* Create the first block from the memory. */ - block = (pj_pool_block*) (buffer + sizeof(*pool)); - block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block); - block->end = buffer + initial_size; - pj_list_insert_after(&pool->block_list, block); - - pj_pool_init_int(pool, name, increment_size, callback); - - /* Pool initial capacity and used size */ - pool->capacity = initial_size; - - LOG((pool->obj_name, "pool created, size=%u", pool->capacity)); - return pool; -} - -/* - * Reset the pool to the state when it was created. - * All blocks will be deallocated except the first block. All memory areas - * are marked as free. - */ -static void reset_pool(pj_pool_t *pool) -{ - pj_pool_block *block; - - PJ_CHECK_STACK(); - - block = pool->block_list.prev; - if (block == &pool->block_list) - return; - - /* Skip the first block because it is occupying the same memory - as the pool itself. - */ - block = block->prev; - - while (block != &pool->block_list) { - pj_pool_block *prev = block->prev; - pj_list_erase(block); - (*pool->factory->policy.block_free)(pool->factory, block, - block->end - (unsigned char*)block); - block = prev; - } - - block = pool->block_list.next; - block->cur = block->buf; - pool->capacity = block->end - (unsigned char*)pool; - pool->used_size = 0; -} - -/* - * The public function to reset pool. - */ -PJ_DEF(void) pj_pool_reset(pj_pool_t *pool) -{ - LOG((pool->obj_name, "reset(): cap=%d, used=%d(%d%%)", - pool->capacity, pool->used_size, pool->used_size*100/pool->capacity)); - - reset_pool(pool); -} - -/* - * Destroy the pool. - */ -PJ_DEF(void) pj_pool_destroy_int(pj_pool_t *pool) -{ - pj_size_t initial_size; - - LOG((pool->obj_name, "destroy(): cap=%d, used=%d(%d%%), block0=%p-%p", - pool->capacity, pool->used_size, pool->used_size*100/pool->capacity, - ((pj_pool_block*)pool->block_list.next)->buf, - ((pj_pool_block*)pool->block_list.next)->end)); - - reset_pool(pool); - initial_size = ((pj_pool_block*)pool->block_list.next)->end - - (unsigned char*)pool; - (*pool->factory->policy.block_free)(pool->factory, pool, initial_size); -} - - +/* $Header: /pjproject-0.3/pjlib/src/pj/pool.c 8 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/pool.c $ + * + * 8 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 7 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include +#include +#include +#include +#include + +/* Include inline definitions when inlining is disabled. */ +#if !PJ_FUNCTIONS_ARE_INLINED +# include +#endif + +#define LOG(expr) PJ_LOG(5,expr) + +int PJ_NO_MEMORY_EXCEPTION; + +/* + * Create new block. + * Create a new big chunk of memory block, from which user allocation will be + * taken from. + */ +static pj_pool_block *pj_pool_create_block( pj_pool_t *pool, pj_size_t size) +{ + pj_pool_block *block; + + PJ_CHECK_STACK(); + pj_assert(size >= sizeof(pj_pool_block)); + + LOG((pool->obj_name, "create_block(sz=%u), cur.cap=%u, cur.used=%u", + size, pool->capacity, pool->used_size)); + + /* Request memory from allocator. */ + block = (pj_pool_block*) + (*pool->factory->policy.block_alloc)(pool->factory, size); + if (block == NULL) { + (*pool->callback)(pool, size); + return NULL; + } + + /* Add capacity. */ + pool->capacity += size; + pool->used_size += sizeof(pj_pool_block); + + /* Set block attribytes. */ + block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block); + block->end = ((unsigned char*)block) + size; + + /* Insert in the front of the list. */ + pj_list_insert_after(&pool->block_list, block); + + LOG((pool->obj_name," block created, buffer=%p-%p",block->buf, block->end)); + + return block; +} + +/* + * Allocate memory chunk for user from available blocks. + * This will iterate through block list to find space to allocate the chunk. + * If no space is available in all the blocks, a new block might be created + * (depending on whether the pool is allowed to resize). + */ +PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size) +{ + pj_pool_block *block = pool->block_list.next; + void *p; + unsigned block_size; + + PJ_CHECK_STACK(); + + while (block != &pool->block_list) { + p = pj_pool_alloc_from_block(pool, block, size); + if (p != NULL) + return p; + block = block->next; + } + /* No available space in all blocks. */ + + /* If pool is configured NOT to expand, return error. */ + if (pool->increment_size == 0) { + LOG((pool->obj_name, "Can't expand pool to allocate %u bytes " + "(used=%u, cap=%u)", + size, pool->used_size, pool->capacity)); + (*pool->callback)(pool, size); + return NULL; + } + + /* If pool is configured to expand, but the increment size + * is less than the required size, expand the pool by multiple + * increment size + */ + if (pool->increment_size < size + sizeof(pj_pool_block)) { + unsigned count; + count = (size + pool->increment_size + sizeof(pj_pool_block)) / + pool->increment_size; + block_size = count * pool->increment_size; + + } else { + block_size = pool->increment_size; + } + + LOG((pool->obj_name, + "%u bytes requested, resizing pool by %u bytes (used=%u, cap=%u)", + size, block_size, pool->used_size, pool->capacity)); + + block = pj_pool_create_block(pool, block_size); + if (!block) + return NULL; + + p = pj_pool_alloc_from_block(pool, block, size); + pj_assert(p != NULL); +#if PJ_DEBUG + if (p == NULL) { + p = p; + } +#endif + return p; +} + +/* + * Internal function to initialize pool. + */ +PJ_DEF(void) pj_pool_init_int( pj_pool_t *pool, + const char *name, + pj_size_t increment_size, + pj_pool_callback *callback) +{ + pj_pool_block *block; + + PJ_CHECK_STACK(); + + pool->increment_size = increment_size; + pool->callback = callback; + pool->used_size = sizeof(*pool); + block = pool->block_list.next; + while (block != &pool->block_list) { + pool->used_size += sizeof(pj_pool_block); + block = block->next; + } + + if (name) { + if (strchr(name, '%') != NULL) { + sprintf(pool->obj_name, name, pool); + } else { + strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME); + } + } else { + pool->obj_name[0] = '\0'; + } +} + +/* + * Create new memory pool. + */ +PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name, + pj_size_t initial_size, + pj_size_t increment_size, + pj_pool_callback *callback) +{ + pj_pool_t *pool; + pj_pool_block *block; + unsigned char *buffer; + + PJ_CHECK_STACK(); + + buffer = (*f->policy.block_alloc)(f, initial_size); + if (!buffer) + return NULL; + + /* Set pool administrative data. */ + pool = (pj_pool_t*)buffer; + pj_memset(pool, 0, sizeof(*pool)); + + pj_list_init(&pool->block_list); + pool->factory = f; + + /* Create the first block from the memory. */ + block = (pj_pool_block*) (buffer + sizeof(*pool)); + block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block); + block->end = buffer + initial_size; + pj_list_insert_after(&pool->block_list, block); + + pj_pool_init_int(pool, name, increment_size, callback); + + /* Pool initial capacity and used size */ + pool->capacity = initial_size; + + LOG((pool->obj_name, "pool created, size=%u", pool->capacity)); + return pool; +} + +/* + * Reset the pool to the state when it was created. + * All blocks will be deallocated except the first block. All memory areas + * are marked as free. + */ +static void reset_pool(pj_pool_t *pool) +{ + pj_pool_block *block; + + PJ_CHECK_STACK(); + + block = pool->block_list.prev; + if (block == &pool->block_list) + return; + + /* Skip the first block because it is occupying the same memory + as the pool itself. + */ + block = block->prev; + + while (block != &pool->block_list) { + pj_pool_block *prev = block->prev; + pj_list_erase(block); + (*pool->factory->policy.block_free)(pool->factory, block, + block->end - (unsigned char*)block); + block = prev; + } + + block = pool->block_list.next; + block->cur = block->buf; + pool->capacity = block->end - (unsigned char*)pool; + pool->used_size = 0; +} + +/* + * The public function to reset pool. + */ +PJ_DEF(void) pj_pool_reset(pj_pool_t *pool) +{ + LOG((pool->obj_name, "reset(): cap=%d, used=%d(%d%%)", + pool->capacity, pool->used_size, pool->used_size*100/pool->capacity)); + + reset_pool(pool); +} + +/* + * Destroy the pool. + */ +PJ_DEF(void) pj_pool_destroy_int(pj_pool_t *pool) +{ + pj_size_t initial_size; + + LOG((pool->obj_name, "destroy(): cap=%d, used=%d(%d%%), block0=%p-%p", + pool->capacity, pool->used_size, pool->used_size*100/pool->capacity, + ((pj_pool_block*)pool->block_list.next)->buf, + ((pj_pool_block*)pool->block_list.next)->end)); + + reset_pool(pool); + initial_size = ((pj_pool_block*)pool->block_list.next)->end - + (unsigned char*)pool; + (*pool->factory->policy.block_free)(pool->factory, pool, initial_size); +} + + diff --git a/pjlib/src/pj/pool_caching.c b/pjlib/src/pj/pool_caching.c index b72b0d45..2bdd6179 100644 --- a/pjlib/src/pj/pool_caching.c +++ b/pjlib/src/pj/pool_caching.c @@ -1,210 +1,210 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/pool_caching.c 5 9/17/05 10:37a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/pool_caching.c $ - * - * 5 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include -#include -#include - -static pj_pool_t* cpool_create_pool(pj_pool_factory *pf, - const char *name, - pj_size_t initial_size, - pj_size_t increment_sz, - pj_pool_callback *callback); -static void cpool_release_pool(pj_pool_factory *pf, pj_pool_t *pool); -static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail ); - -static pj_size_t pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE] = -{ - 256, 512, 1024, 2048, 4096, 8192, 12288, 16384, - 20480, 24576, 28672, 32768, 40960, 49152, 57344, 65536 -}; - - -PJ_DEF(void) pj_caching_pool_init( pj_caching_pool *cp, - const pj_pool_factory_policy *policy, - pj_size_t max_capacity) -{ - int i; - - PJ_CHECK_STACK(); - - pj_memset(cp, 0, sizeof(*cp)); - - cp->max_capacity = max_capacity; - pj_list_init(&cp->used_list); - for (i=0; ifree_list[i]); - - pj_memcpy(&cp->factory.policy, policy, sizeof(pj_pool_factory_policy)); - cp->factory.create_pool = &cpool_create_pool; - cp->factory.release_pool = &cpool_release_pool; - cp->factory.dump_status = &cpool_dump_status; -} - -PJ_DEF(void) pj_caching_pool_destroy( pj_caching_pool *cp ) -{ - int i; - pj_pool_t *pool; - - PJ_CHECK_STACK(); - - /* Delete all pool in free list */ - for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE; ++i) { - pj_pool_t *pool = cp->free_list[i].next; - pj_pool_t *next; - for (; pool != (void*)&cp->free_list[i]; pool = next) { - next = pool->next; - pj_list_erase(pool); - pj_pool_destroy_int(pool); - } - } - - /* Delete all pools in used list */ - pool = cp->used_list.next; - while (pool != (pj_pool_t*) &cp->used_list) { - pj_pool_t *next = pool->next; - pj_list_erase(pool); - pj_pool_destroy_int(pool); - pool = next; - } -} - -static pj_pool_t* cpool_create_pool(pj_pool_factory *pf, - const char *name, - pj_size_t initial_size, - pj_size_t increment_sz, - pj_pool_callback *callback) -{ - pj_caching_pool *cp = (pj_caching_pool*)pf; - pj_pool_t *pool; - int idx; - - PJ_CHECK_STACK(); - - /* Use pool factory's policy when callback is NULL */ - if (callback == NULL) { - callback = pf->policy.callback; - } - - /* Search the suitable size for the pool. - * We'll just do linear search to the size array, as the array size itself - * is only a few elements. Binary search I suspect will be less efficient - * for this purpose. - */ - for (idx=0; - idx < PJ_CACHING_POOL_ARRAY_SIZE && pool_sizes[idx] < initial_size; - ++idx) - ; - - /* Check whether there's a pool in the list. */ - if (idx==PJ_CACHING_POOL_ARRAY_SIZE || pj_list_empty(&cp->free_list[idx])) { - /* No pool is available. */ - /* Set minimum size. */ - if (idx < PJ_CACHING_POOL_ARRAY_SIZE) - initial_size = pool_sizes[idx]; - - /* Create new pool */ - pool = pj_pool_create_int(&cp->factory, name, initial_size, - increment_sz, callback); - if (!pool) - return NULL; - - } else { - /* Get one pool from the list. */ - pool = cp->free_list[idx].next; - pj_list_erase(pool); - - /* Initialize the pool. */ - pj_pool_init_int(pool, name, increment_sz, callback); - - /* Update pool manager's free capacity. */ - cp->capacity -= pj_pool_get_capacity(pool); - - PJ_LOG(5, (pool->obj_name, "pool reused, size=%u", pool->capacity)); - } - - /* Put in used list. */ - pj_list_insert_before( &cp->used_list, pool ); - - /* Increment used count. */ - ++cp->used_count; - return pool; -} - -static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool) -{ - pj_caching_pool *cp = (pj_caching_pool*)pf; - int i; - - PJ_CHECK_STACK(); - - /* Erase from the used list. */ - pj_list_erase(pool); - - /* Decrement used count. */ - --cp->used_count; - - /* Destroy the pool if the size is greater than our size or if the total - * capacity in our recycle list (plus the size of the pool) exceeds - * maximum capacity. - . */ - if (pool->capacity > pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE-1] || - cp->capacity + pool->capacity > cp->max_capacity) - { - pj_pool_destroy_int(pool); - return; - } - - /* Reset pool. */ - PJ_LOG(4, (pool->obj_name, "recycle(): cap=%d, used=%d(%d%%)", - pool->capacity, pool->used_size, pool->used_size*100/pool->capacity)); - pj_pool_reset(pool); - - /* - * Otherwise put the pool in our recycle list. - */ - for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE && pool_sizes[i] != pool->capacity; ++i) - ; - - pj_assert( i != PJ_CACHING_POOL_ARRAY_SIZE ); - if (i == PJ_CACHING_POOL_ARRAY_SIZE) { - /* Something has gone wrong with the pool. */ - pj_pool_destroy_int(pool); - return; - } - - pj_list_insert_after(&cp->free_list[i], pool); - cp->capacity += pool->capacity; -} - -static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail ) -{ -#if PJ_LOG_MAX_LEVEL >= 3 - pj_caching_pool *cp = (pj_caching_pool*)factory; - PJ_LOG(3,("cachpool", " Dumping caching pool:")); - PJ_LOG(3,("cachpool", " Capacity=%u, max_capacity=%u, used_cnt=%u", \ - cp->capacity, cp->max_capacity, cp->used_count)); - if (detail) { - pj_pool_t *pool = cp->used_list.next; - pj_uint32_t total_used = 0, total_capacity = 0; - PJ_LOG(3,("cachpool", " Dumping all active pools:")); - while (pool != (void*)&cp->used_list) { - PJ_LOG(3,("cachpool", " %12s: %8d of %8d (%d%%) used", pool->obj_name, - pool->used_size, pool->capacity, - pool->used_size*100/pool->capacity)); - total_used += pool->used_size; - total_capacity += pool->capacity; - pool = pool->next; - } - PJ_LOG(3,("cachpool", " Total %9d of %9d (%d %%) used!", - total_used, total_capacity, - total_used * 100 / total_capacity)); - } -#endif -} +/* $Header: /pjproject-0.3/pjlib/src/pj/pool_caching.c 5 9/17/05 10:37a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/pool_caching.c $ + * + * 5 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include +#include +#include +#include + +static pj_pool_t* cpool_create_pool(pj_pool_factory *pf, + const char *name, + pj_size_t initial_size, + pj_size_t increment_sz, + pj_pool_callback *callback); +static void cpool_release_pool(pj_pool_factory *pf, pj_pool_t *pool); +static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail ); + +static pj_size_t pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE] = +{ + 256, 512, 1024, 2048, 4096, 8192, 12288, 16384, + 20480, 24576, 28672, 32768, 40960, 49152, 57344, 65536 +}; + + +PJ_DEF(void) pj_caching_pool_init( pj_caching_pool *cp, + const pj_pool_factory_policy *policy, + pj_size_t max_capacity) +{ + int i; + + PJ_CHECK_STACK(); + + pj_memset(cp, 0, sizeof(*cp)); + + cp->max_capacity = max_capacity; + pj_list_init(&cp->used_list); + for (i=0; ifree_list[i]); + + pj_memcpy(&cp->factory.policy, policy, sizeof(pj_pool_factory_policy)); + cp->factory.create_pool = &cpool_create_pool; + cp->factory.release_pool = &cpool_release_pool; + cp->factory.dump_status = &cpool_dump_status; +} + +PJ_DEF(void) pj_caching_pool_destroy( pj_caching_pool *cp ) +{ + int i; + pj_pool_t *pool; + + PJ_CHECK_STACK(); + + /* Delete all pool in free list */ + for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE; ++i) { + pj_pool_t *pool = cp->free_list[i].next; + pj_pool_t *next; + for (; pool != (void*)&cp->free_list[i]; pool = next) { + next = pool->next; + pj_list_erase(pool); + pj_pool_destroy_int(pool); + } + } + + /* Delete all pools in used list */ + pool = cp->used_list.next; + while (pool != (pj_pool_t*) &cp->used_list) { + pj_pool_t *next = pool->next; + pj_list_erase(pool); + pj_pool_destroy_int(pool); + pool = next; + } +} + +static pj_pool_t* cpool_create_pool(pj_pool_factory *pf, + const char *name, + pj_size_t initial_size, + pj_size_t increment_sz, + pj_pool_callback *callback) +{ + pj_caching_pool *cp = (pj_caching_pool*)pf; + pj_pool_t *pool; + int idx; + + PJ_CHECK_STACK(); + + /* Use pool factory's policy when callback is NULL */ + if (callback == NULL) { + callback = pf->policy.callback; + } + + /* Search the suitable size for the pool. + * We'll just do linear search to the size array, as the array size itself + * is only a few elements. Binary search I suspect will be less efficient + * for this purpose. + */ + for (idx=0; + idx < PJ_CACHING_POOL_ARRAY_SIZE && pool_sizes[idx] < initial_size; + ++idx) + ; + + /* Check whether there's a pool in the list. */ + if (idx==PJ_CACHING_POOL_ARRAY_SIZE || pj_list_empty(&cp->free_list[idx])) { + /* No pool is available. */ + /* Set minimum size. */ + if (idx < PJ_CACHING_POOL_ARRAY_SIZE) + initial_size = pool_sizes[idx]; + + /* Create new pool */ + pool = pj_pool_create_int(&cp->factory, name, initial_size, + increment_sz, callback); + if (!pool) + return NULL; + + } else { + /* Get one pool from the list. */ + pool = cp->free_list[idx].next; + pj_list_erase(pool); + + /* Initialize the pool. */ + pj_pool_init_int(pool, name, increment_sz, callback); + + /* Update pool manager's free capacity. */ + cp->capacity -= pj_pool_get_capacity(pool); + + PJ_LOG(5, (pool->obj_name, "pool reused, size=%u", pool->capacity)); + } + + /* Put in used list. */ + pj_list_insert_before( &cp->used_list, pool ); + + /* Increment used count. */ + ++cp->used_count; + return pool; +} + +static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool) +{ + pj_caching_pool *cp = (pj_caching_pool*)pf; + int i; + + PJ_CHECK_STACK(); + + /* Erase from the used list. */ + pj_list_erase(pool); + + /* Decrement used count. */ + --cp->used_count; + + /* Destroy the pool if the size is greater than our size or if the total + * capacity in our recycle list (plus the size of the pool) exceeds + * maximum capacity. + . */ + if (pool->capacity > pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE-1] || + cp->capacity + pool->capacity > cp->max_capacity) + { + pj_pool_destroy_int(pool); + return; + } + + /* Reset pool. */ + PJ_LOG(4, (pool->obj_name, "recycle(): cap=%d, used=%d(%d%%)", + pool->capacity, pool->used_size, pool->used_size*100/pool->capacity)); + pj_pool_reset(pool); + + /* + * Otherwise put the pool in our recycle list. + */ + for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE && pool_sizes[i] != pool->capacity; ++i) + ; + + pj_assert( i != PJ_CACHING_POOL_ARRAY_SIZE ); + if (i == PJ_CACHING_POOL_ARRAY_SIZE) { + /* Something has gone wrong with the pool. */ + pj_pool_destroy_int(pool); + return; + } + + pj_list_insert_after(&cp->free_list[i], pool); + cp->capacity += pool->capacity; +} + +static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail ) +{ +#if PJ_LOG_MAX_LEVEL >= 3 + pj_caching_pool *cp = (pj_caching_pool*)factory; + PJ_LOG(3,("cachpool", " Dumping caching pool:")); + PJ_LOG(3,("cachpool", " Capacity=%u, max_capacity=%u, used_cnt=%u", \ + cp->capacity, cp->max_capacity, cp->used_count)); + if (detail) { + pj_pool_t *pool = cp->used_list.next; + pj_uint32_t total_used = 0, total_capacity = 0; + PJ_LOG(3,("cachpool", " Dumping all active pools:")); + while (pool != (void*)&cp->used_list) { + PJ_LOG(3,("cachpool", " %12s: %8d of %8d (%d%%) used", pool->obj_name, + pool->used_size, pool->capacity, + pool->used_size*100/pool->capacity)); + total_used += pool->used_size; + total_capacity += pool->capacity; + pool = pool->next; + } + PJ_LOG(3,("cachpool", " Total %9d of %9d (%d %%) used!", + total_used, total_capacity, + total_used * 100 / total_capacity)); + } +#endif +} diff --git a/pjlib/src/pj/pool_dbg_win32.c b/pjlib/src/pj/pool_dbg_win32.c index 4419d048..a4d404db 100644 --- a/pjlib/src/pj/pool_dbg_win32.c +++ b/pjlib/src/pj/pool_dbg_win32.c @@ -1,226 +1,226 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/pool_dbg_win32.c 4 9/17/05 10:37a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/pool_dbg_win32.c $ - * - * 4 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include - -/* Only if we ARE debugging memory allocations. */ -#if PJ_POOL_DEBUG - -#include -#include - -#include -#include -#define WIN32_LEAN_AND_MEAN -#include - -typedef struct memory_entry -{ - PJ_DECL_LIST_MEMBER(struct memory_entry) - void *ptr; - char *file; - int line; -} memory_entry; - -struct pj_pool_t -{ - char obj_name[32]; - HANDLE hHeap; - memory_entry first; - pj_size_t initial_size; - pj_size_t increment; - pj_size_t used_size; - char *file; - int line; -}; - -PJ_DEF(void) pj_pool_set_functions( void *(*malloc_func)(pj_size_t), - void (*free_func)(void *ptr, pj_size_t)) -{ - /* Ignored. */ - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(malloc_func) - PJ_UNUSED_ARG(free_func) -} - -PJ_DEF(pj_pool_t*) pj_pool_create_dbg( const char *name, - pj_size_t initial_size, - pj_size_t increment_size, - pj_pool_callback *callback, - char *file, int line) -{ - pj_pool_t *pool; - HANDLE hHeap; - - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(callback) - - /* Create Win32 heap for the pool. */ - hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE, - initial_size, 0); - if (!hHeap) { - return NULL; - } - - - /* Create and initialize the pool structure. */ - pool = HeapAlloc(hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE, - sizeof(*pool)); - memset(pool, 0, sizeof(*pool)); - pool->file = file; - pool->line = line; - pool->hHeap = hHeap; - pool->initial_size = initial_size; - pool->increment = increment_size; - pool->used_size = 0; - - /* Set name. */ - if (name) { - if (strchr(name, '%') != NULL) { - sprintf(pool->obj_name, name, pool); - } else { - strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME); - } - } else { - pool->obj_name[0] = '\0'; - } - - /* List pool's entry. */ - pj_list_init(&pool->first); - - PJ_LOG(3,(pool->obj_name, "Pool created")); - return pool; -} - -PJ_DEF(void) pj_pool_destroy( pj_pool_t *pool ) -{ - memory_entry *entry; - - PJ_CHECK_STACK(); - - PJ_LOG(3,(pool->obj_name, "Destoying pool, init_size=%u, used=%u", - pool->initial_size, pool->used_size)); - - if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, pool)) { - PJ_LOG(2,(pool->obj_name, "Corrupted pool structure, allocated in %s:%d", - pool->file, pool->line)); - } - - /* Validate all memory entries in the pool. */ - for (entry=pool->first.next; entry != &pool->first; entry = entry->next) { - if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, entry)) { - PJ_LOG(2,(pool->obj_name, "Corrupted pool entry, allocated in %s:%d", - entry->file, entry->line)); - } - - if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, entry->ptr)) { - PJ_LOG(2,(pool->obj_name, "Corrupted pool memory, allocated in %s:%d", - entry->file, entry->line)); - } - } - - /* Destroy heap. */ - HeapDestroy(pool->hHeap); -} - -PJ_DEF(void) pj_pool_reset( pj_pool_t *pool ) -{ - /* Do nothing. */ - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(pool) -} - -PJ_DEF(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool ) -{ - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(pool) - return 0; -} - -PJ_DEF(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool ) -{ - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(pool) - return 0; -} - -PJ_DEF(pj_size_t) pj_pool_get_request_count( pj_pool_t *pool ) -{ - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(pool) - return 0; -} - -PJ_DEF(void*) pj_pool_alloc_dbg( pj_pool_t *pool, pj_size_t size, - char *file, int line) -{ - memory_entry *entry; - int entry_size; - - PJ_CHECK_STACK(); - - entry_size = sizeof(*entry); - entry = HeapAlloc(pool->hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE, - entry_size); - entry->file = file; - entry->line = line; - entry->ptr = HeapAlloc(pool->hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE, - size); - pj_list_insert_before( &pool->first, entry); - - pool->used_size += size; - return entry->ptr; -} - -PJ_DEF(void*) pj_pool_calloc_dbg( pj_pool_t *pool, pj_size_t count, pj_size_t elem, - char *file, int line) -{ - void *ptr; - - PJ_CHECK_STACK(); - - ptr = pj_pool_alloc_dbg(pool, count*elem, file, line); - memset(ptr, 0, count*elem); - return ptr; -} - - -PJ_DEF(void) pj_pool_pool_init( pj_pool_pool_t *pool_pool, - pj_size_t max_capacity) -{ - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(pool_pool) - PJ_UNUSED_ARG(max_capacity) -} - -PJ_DEF(void) pj_pool_pool_destroy( pj_pool_pool_t *pool_pool ) -{ - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(pool_pool) -} - -PJ_DEF(pj_pool_t*) pj_pool_pool_create_pool( pj_pool_pool_t *pool_pool, - const char *name, - pj_size_t initial_size, - pj_size_t increment_size, - pj_pool_callback *callback) -{ - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(pool_pool) - return pj_pool_create(name, initial_size, increment_size, callback); -} - -PJ_DEF(void) pj_pool_pool_release_pool( pj_pool_pool_t *pool_pool, - pj_pool_t *pool ) -{ - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(pool_pool) - pj_pool_destroy(pool); -} - - -#endif /* PJ_POOL_DEBUG */ +/* $Header: /pjproject-0.3/pjlib/src/pj/pool_dbg_win32.c 4 9/17/05 10:37a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/pool_dbg_win32.c $ + * + * 4 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include + +/* Only if we ARE debugging memory allocations. */ +#if PJ_POOL_DEBUG + +#include +#include + +#include +#include +#define WIN32_LEAN_AND_MEAN +#include + +typedef struct memory_entry +{ + PJ_DECL_LIST_MEMBER(struct memory_entry) + void *ptr; + char *file; + int line; +} memory_entry; + +struct pj_pool_t +{ + char obj_name[32]; + HANDLE hHeap; + memory_entry first; + pj_size_t initial_size; + pj_size_t increment; + pj_size_t used_size; + char *file; + int line; +}; + +PJ_DEF(void) pj_pool_set_functions( void *(*malloc_func)(pj_size_t), + void (*free_func)(void *ptr, pj_size_t)) +{ + /* Ignored. */ + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(malloc_func) + PJ_UNUSED_ARG(free_func) +} + +PJ_DEF(pj_pool_t*) pj_pool_create_dbg( const char *name, + pj_size_t initial_size, + pj_size_t increment_size, + pj_pool_callback *callback, + char *file, int line) +{ + pj_pool_t *pool; + HANDLE hHeap; + + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(callback) + + /* Create Win32 heap for the pool. */ + hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE, + initial_size, 0); + if (!hHeap) { + return NULL; + } + + + /* Create and initialize the pool structure. */ + pool = HeapAlloc(hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE, + sizeof(*pool)); + memset(pool, 0, sizeof(*pool)); + pool->file = file; + pool->line = line; + pool->hHeap = hHeap; + pool->initial_size = initial_size; + pool->increment = increment_size; + pool->used_size = 0; + + /* Set name. */ + if (name) { + if (strchr(name, '%') != NULL) { + sprintf(pool->obj_name, name, pool); + } else { + strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME); + } + } else { + pool->obj_name[0] = '\0'; + } + + /* List pool's entry. */ + pj_list_init(&pool->first); + + PJ_LOG(3,(pool->obj_name, "Pool created")); + return pool; +} + +PJ_DEF(void) pj_pool_destroy( pj_pool_t *pool ) +{ + memory_entry *entry; + + PJ_CHECK_STACK(); + + PJ_LOG(3,(pool->obj_name, "Destoying pool, init_size=%u, used=%u", + pool->initial_size, pool->used_size)); + + if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, pool)) { + PJ_LOG(2,(pool->obj_name, "Corrupted pool structure, allocated in %s:%d", + pool->file, pool->line)); + } + + /* Validate all memory entries in the pool. */ + for (entry=pool->first.next; entry != &pool->first; entry = entry->next) { + if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, entry)) { + PJ_LOG(2,(pool->obj_name, "Corrupted pool entry, allocated in %s:%d", + entry->file, entry->line)); + } + + if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, entry->ptr)) { + PJ_LOG(2,(pool->obj_name, "Corrupted pool memory, allocated in %s:%d", + entry->file, entry->line)); + } + } + + /* Destroy heap. */ + HeapDestroy(pool->hHeap); +} + +PJ_DEF(void) pj_pool_reset( pj_pool_t *pool ) +{ + /* Do nothing. */ + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(pool) +} + +PJ_DEF(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool ) +{ + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(pool) + return 0; +} + +PJ_DEF(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool ) +{ + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(pool) + return 0; +} + +PJ_DEF(pj_size_t) pj_pool_get_request_count( pj_pool_t *pool ) +{ + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(pool) + return 0; +} + +PJ_DEF(void*) pj_pool_alloc_dbg( pj_pool_t *pool, pj_size_t size, + char *file, int line) +{ + memory_entry *entry; + int entry_size; + + PJ_CHECK_STACK(); + + entry_size = sizeof(*entry); + entry = HeapAlloc(pool->hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE, + entry_size); + entry->file = file; + entry->line = line; + entry->ptr = HeapAlloc(pool->hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE, + size); + pj_list_insert_before( &pool->first, entry); + + pool->used_size += size; + return entry->ptr; +} + +PJ_DEF(void*) pj_pool_calloc_dbg( pj_pool_t *pool, pj_size_t count, pj_size_t elem, + char *file, int line) +{ + void *ptr; + + PJ_CHECK_STACK(); + + ptr = pj_pool_alloc_dbg(pool, count*elem, file, line); + memset(ptr, 0, count*elem); + return ptr; +} + + +PJ_DEF(void) pj_pool_pool_init( pj_pool_pool_t *pool_pool, + pj_size_t max_capacity) +{ + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(pool_pool) + PJ_UNUSED_ARG(max_capacity) +} + +PJ_DEF(void) pj_pool_pool_destroy( pj_pool_pool_t *pool_pool ) +{ + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(pool_pool) +} + +PJ_DEF(pj_pool_t*) pj_pool_pool_create_pool( pj_pool_pool_t *pool_pool, + const char *name, + pj_size_t initial_size, + pj_size_t increment_size, + pj_pool_callback *callback) +{ + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(pool_pool) + return pj_pool_create(name, initial_size, increment_size, callback); +} + +PJ_DEF(void) pj_pool_pool_release_pool( pj_pool_pool_t *pool_pool, + pj_pool_t *pool ) +{ + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(pool_pool) + pj_pool_destroy(pool); +} + + +#endif /* PJ_POOL_DEBUG */ diff --git a/pjlib/src/pj/pool_policy_kmalloc.c b/pjlib/src/pj/pool_policy_kmalloc.c index 4accff7d..0c7f8101 100644 --- a/pjlib/src/pj/pool_policy_kmalloc.c +++ b/pjlib/src/pj/pool_policy_kmalloc.c @@ -1,54 +1,54 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/pool_policy_kmalloc.c 3 10/29/05 11:51a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/pool_policy_kmalloc.c $ - * - * 3 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 9/22/05 10:40a Bennylp - * Created. - * - */ -#include -#include -#include - - -static void *default_block_alloc(pj_pool_factory *factory, pj_size_t size) -{ - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(factory); - - return kmalloc(size, GFP_ATOMIC); -} - -static void default_block_free(pj_pool_factory *factory, - void *mem, pj_size_t size) -{ - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(factory); - PJ_UNUSED_ARG(size); - - kfree(mem); -} - -static void default_pool_callback(pj_pool_t *pool, pj_size_t size) -{ - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(pool); - PJ_UNUSED_ARG(size); - - PJ_THROW(PJ_NO_MEMORY_EXCEPTION); -} - -pj_pool_factory_policy pj_pool_factory_default_policy = -{ - &default_block_alloc, - &default_block_free, - &default_pool_callback, - 0 -}; - +/* $Header: /pjproject-0.3/pjlib/src/pj/pool_policy_kmalloc.c 3 10/29/05 11:51a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/pool_policy_kmalloc.c $ + * + * 3 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 9/22/05 10:40a Bennylp + * Created. + * + */ +#include +#include +#include + + +static void *default_block_alloc(pj_pool_factory *factory, pj_size_t size) +{ + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(factory); + + return kmalloc(size, GFP_ATOMIC); +} + +static void default_block_free(pj_pool_factory *factory, + void *mem, pj_size_t size) +{ + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(factory); + PJ_UNUSED_ARG(size); + + kfree(mem); +} + +static void default_pool_callback(pj_pool_t *pool, pj_size_t size) +{ + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(pool); + PJ_UNUSED_ARG(size); + + PJ_THROW(PJ_NO_MEMORY_EXCEPTION); +} + +pj_pool_factory_policy pj_pool_factory_default_policy = +{ + &default_block_alloc, + &default_block_free, + &default_pool_callback, + 0 +}; + diff --git a/pjlib/src/pj/pool_policy_malloc.c b/pjlib/src/pj/pool_policy_malloc.c index 12eb7c34..eb31deea 100644 --- a/pjlib/src/pj/pool_policy_malloc.c +++ b/pjlib/src/pj/pool_policy_malloc.c @@ -1,58 +1,58 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/pool_policy_malloc.c 2 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/pool_policy_malloc.c $ - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 9/21/05 1:37p Bennylp - * Renamed from pool_policy.c - * - * 3 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include -#include - -/* - * This file contains pool default policy definition and implementation. - */ - - -static void *default_block_alloc(pj_pool_factory *factory, pj_size_t size) -{ - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(factory); - PJ_UNUSED_ARG(size); - - return malloc(size); -} - -static void default_block_free(pj_pool_factory *factory, void *mem, pj_size_t size) -{ - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(factory); - PJ_UNUSED_ARG(size); - - free(mem); -} - -static void default_pool_callback(pj_pool_t *pool, pj_size_t size) -{ - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(pool); - PJ_UNUSED_ARG(size); - - PJ_THROW(PJ_NO_MEMORY_EXCEPTION); -} - -pj_pool_factory_policy pj_pool_factory_default_policy = -{ - &default_block_alloc, - &default_block_free, - &default_pool_callback, - 0 -}; +/* $Header: /pjproject-0.3/pjlib/src/pj/pool_policy_malloc.c 2 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/pool_policy_malloc.c $ + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 9/21/05 1:37p Bennylp + * Renamed from pool_policy.c + * + * 3 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include +#include +#include + +/* + * This file contains pool default policy definition and implementation. + */ + + +static void *default_block_alloc(pj_pool_factory *factory, pj_size_t size) +{ + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(factory); + PJ_UNUSED_ARG(size); + + return malloc(size); +} + +static void default_block_free(pj_pool_factory *factory, void *mem, pj_size_t size) +{ + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(factory); + PJ_UNUSED_ARG(size); + + free(mem); +} + +static void default_pool_callback(pj_pool_t *pool, pj_size_t size) +{ + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(pool); + PJ_UNUSED_ARG(size); + + PJ_THROW(PJ_NO_MEMORY_EXCEPTION); +} + +pj_pool_factory_policy pj_pool_factory_default_policy = +{ + &default_block_alloc, + &default_block_free, + &default_pool_callback, + 0 +}; diff --git a/pjlib/src/pj/rand.c b/pjlib/src/pj/rand.c index 6d25670f..2e0065db 100644 --- a/pjlib/src/pj/rand.c +++ b/pjlib/src/pj/rand.c @@ -1,29 +1,29 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/rand.c 3 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/rand.c $ - * - * 3 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - * 1 9/15/05 8:40p Bennylp - * Created. - */ -#include -#include -#include - -PJ_DEF(void) pj_srand(unsigned int seed) -{ - PJ_CHECK_STACK(); - platform_srand(seed); -} - -PJ_DEF(int) pj_rand(void) -{ - PJ_CHECK_STACK(); - return platform_rand(); -} - +/* $Header: /pjproject-0.3/pjlib/src/pj/rand.c 3 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/rand.c $ + * + * 3 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 2 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + * 1 9/15/05 8:40p Bennylp + * Created. + */ +#include +#include +#include + +PJ_DEF(void) pj_srand(unsigned int seed) +{ + PJ_CHECK_STACK(); + platform_srand(seed); +} + +PJ_DEF(int) pj_rand(void) +{ + PJ_CHECK_STACK(); + return platform_rand(); +} + diff --git a/pjlib/src/pj/rbtree.c b/pjlib/src/pj/rbtree.c index 582a6f75..027084e7 100644 --- a/pjlib/src/pj/rbtree.c +++ b/pjlib/src/pj/rbtree.c @@ -1,416 +1,416 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/rbtree.c 5 9/17/05 10:37a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/rbtree.c $ - * - * 5 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include - -static void left_rotate( pj_rbtree *tree, pj_rbtree_node *node ) -{ - pj_rbtree_node *rnode, *parent; - - PJ_CHECK_STACK(); - - rnode = node->right; - if (rnode == tree->null) - return; - - node->right = rnode->left; - if (rnode->left != tree->null) - rnode->left->parent = node; - parent = node->parent; - rnode->parent = parent; - if (parent != tree->null) { - if (parent->left == node) - parent->left = rnode; - else - parent->right = rnode; - } else { - tree->root = rnode; - } - rnode->left = node; - node->parent = rnode; -} - -static void right_rotate( pj_rbtree *tree, pj_rbtree_node *node ) -{ - pj_rbtree_node *lnode, *parent; - - PJ_CHECK_STACK(); - - lnode = node->left; - if (lnode == tree->null) - return; - - node->left = lnode->right; - if (lnode->right != tree->null) - lnode->right->parent = node; - parent = node->parent; - lnode->parent = parent; - - if (parent != tree->null) { - if (parent->left == node) - parent->left = lnode; - else - parent->right = lnode; - } else { - tree->root = lnode; - } - lnode->right = node; - node->parent = lnode; -} - -static void insert_fixup( pj_rbtree *tree, pj_rbtree_node *node ) -{ - pj_rbtree_node *temp, *parent; - - PJ_CHECK_STACK(); - - while (node != tree->root && node->parent->color == PJ_RBCOLOR_RED) { - parent = node->parent; - if (parent == parent->parent->left) { - temp = parent->parent->right; - if (temp->color == PJ_RBCOLOR_RED) { - temp->color = PJ_RBCOLOR_BLACK; - node = parent; - node->color = PJ_RBCOLOR_BLACK; - node = node->parent; - node->color = PJ_RBCOLOR_RED; - } else { - if (node == parent->right) { - node = parent; - left_rotate(tree, node); - } - temp = node->parent; - temp->color = PJ_RBCOLOR_BLACK; - temp = temp->parent; - temp->color = PJ_RBCOLOR_RED; - right_rotate( tree, temp); - } - } else { - temp = parent->parent->left; - if (temp->color == PJ_RBCOLOR_RED) { - temp->color = PJ_RBCOLOR_BLACK; - node = parent; - node->color = PJ_RBCOLOR_BLACK; - node = node->parent; - node->color = PJ_RBCOLOR_RED; - } else { - if (node == parent->left) { - node = parent; - right_rotate(tree, node); - } - temp = node->parent; - temp->color = PJ_RBCOLOR_BLACK; - temp = temp->parent; - temp->color = PJ_RBCOLOR_RED; - left_rotate(tree, temp); - } - } - } - - tree->root->color = PJ_RBCOLOR_BLACK; -} - - -static void delete_fixup( pj_rbtree *tree, pj_rbtree_node *node ) -{ - pj_rbtree_node *temp; - - PJ_CHECK_STACK(); - - while (node != tree->root && node->color == PJ_RBCOLOR_BLACK) { - if (node->parent->left == node) { - temp = node->parent->right; - if (temp->color == PJ_RBCOLOR_RED) { - temp->color = PJ_RBCOLOR_BLACK; - node->parent->color = PJ_RBCOLOR_RED; - left_rotate(tree, node->parent); - temp = node->parent->right; - } - if (temp->left->color == PJ_RBCOLOR_BLACK && - temp->right->color == PJ_RBCOLOR_BLACK) - { - temp->color = PJ_RBCOLOR_RED; - node = node->parent; - } else { - if (temp->right->color == PJ_RBCOLOR_BLACK) { - temp->left->color = PJ_RBCOLOR_BLACK; - temp->color = PJ_RBCOLOR_RED; - right_rotate( tree, temp); - temp = node->parent->right; - } - temp->color = node->parent->color; - temp->right->color = PJ_RBCOLOR_BLACK; - node->parent->color = PJ_RBCOLOR_BLACK; - left_rotate(tree, node->parent); - node = tree->root; - } - } else { - temp = node->parent->left; - if (temp->color == PJ_RBCOLOR_RED) { - temp->color = PJ_RBCOLOR_BLACK; - node->parent->color = PJ_RBCOLOR_RED; - right_rotate( tree, node->parent); - temp = node->parent->left; - } - if (temp->right->color == PJ_RBCOLOR_BLACK && - temp->left->color == PJ_RBCOLOR_BLACK) - { - temp->color = PJ_RBCOLOR_RED; - node = node->parent; - } else { - if (temp->left->color == PJ_RBCOLOR_BLACK) { - temp->right->color = PJ_RBCOLOR_BLACK; - temp->color = PJ_RBCOLOR_RED; - left_rotate( tree, temp); - temp = node->parent->left; - } - temp->color = node->parent->color; - node->parent->color = PJ_RBCOLOR_BLACK; - temp->left->color = PJ_RBCOLOR_BLACK; - right_rotate(tree, node->parent); - node = tree->root; - } - } - } - - node->color = PJ_RBCOLOR_BLACK; -} - - -PJ_DEF(void) pj_rbtree_init( pj_rbtree *tree, pj_rbtree_comp *comp ) -{ - PJ_CHECK_STACK(); - - tree->null = tree->root = &tree->null_node; - tree->null->key = NULL; - tree->null->user_data = NULL; - tree->size = 0; - tree->null->left = tree->null->right = tree->null->parent = tree->null; - tree->null->color = PJ_RBCOLOR_BLACK; - tree->comp = comp; -} - -PJ_DEF(pj_rbtree_node*) pj_rbtree_first( pj_rbtree *tree ) -{ - register pj_rbtree_node *node = tree->root; - register pj_rbtree_node *null = tree->null; - - PJ_CHECK_STACK(); - - while (node->left != null) - node = node->left; - return node != null ? node : NULL; -} - -PJ_DEF(pj_rbtree_node*) pj_rbtree_last( pj_rbtree *tree ) -{ - register pj_rbtree_node *node = tree->root; - register pj_rbtree_node *null = tree->null; - - PJ_CHECK_STACK(); - - while (node->right != null) - node = node->right; - return node != null ? node : NULL; -} - -PJ_DEF(pj_rbtree_node*) pj_rbtree_next( pj_rbtree *tree, - register pj_rbtree_node *node ) -{ - register pj_rbtree_node *null = tree->null; - - PJ_CHECK_STACK(); - - if (node->right != null) { - for (node=node->right; node->left!=null; node = node->left) - /* void */; - } else { - register pj_rbtree_node *temp = node->parent; - while (temp!=null && temp->right==node) { - node = temp; - temp = temp->parent; - } - node = temp; - } - return node != null ? node : NULL; -} - -PJ_DEF(pj_rbtree_node*) pj_rbtree_prev( pj_rbtree *tree, - register pj_rbtree_node *node ) -{ - register pj_rbtree_node *null = tree->null; - - PJ_CHECK_STACK(); - - if (node->left != null) { - for (node=node->left; node->right!=null; node=node->right) - /* void */; - } else { - register pj_rbtree_node *temp = node->parent; - while (temp!=null && temp->left==node) { - node = temp; - temp = temp->parent; - } - node = temp; - } - return node != null ? node : NULL; -} - -PJ_DEF(int) pj_rbtree_insert( pj_rbtree *tree, - pj_rbtree_node *element ) -{ - int rv = 0; - pj_rbtree_node *node, *parent = tree->null, - *null = tree->null; - pj_rbtree_comp *comp = tree->comp; - - PJ_CHECK_STACK(); - - node = tree->root; - while (node != null) { - rv = (*comp)(element->key, node->key); - if (rv == 0) { - /* found match, i.e. entry with equal key already exist */ - return -1; - } - parent = node; - node = rv < 0 ? node->left : node->right; - } - - element->color = PJ_RBCOLOR_RED; - element->left = element->right = null; - - node = element; - if (parent != null) { - node->parent = parent; - if (rv < 0) - parent->left = node; - else - parent->right = node; - insert_fixup( tree, node); - } else { - tree->root = node; - node->parent = null; - node->color = PJ_RBCOLOR_BLACK; - } - - ++tree->size; - return 0; -} - - -PJ_DEF(pj_rbtree_node*) pj_rbtree_find( pj_rbtree *tree, - const void *key ) -{ - int rv; - pj_rbtree_node *node = tree->root; - pj_rbtree_node *null = tree->null; - pj_rbtree_comp *comp = tree->comp; - - while (node != null) { - rv = (*comp)(key, node->key); - if (rv == 0) - return node; - node = rv < 0 ? node->left : node->right; - } - return node != null ? node : NULL; -} - -PJ_DEF(pj_rbtree_node*) pj_rbtree_erase( pj_rbtree *tree, - pj_rbtree_node *node ) -{ - pj_rbtree_node *succ; - pj_rbtree_node *null = tree->null; - pj_rbtree_node *child; - pj_rbtree_node *parent; - - PJ_CHECK_STACK(); - - if (node->left == null || node->right == null) { - succ = node; - } else { - for (succ=node->right; succ->left!=null; succ=succ->left) - /* void */; - } - - child = succ->left != null ? succ->left : succ->right; - parent = succ->parent; - child->parent = parent; - - if (parent != null) { - if (parent->left == succ) - parent->left = child; - else - parent->right = child; - } else - tree->root = child; - - if (succ != node) { - succ->parent = node->parent; - succ->left = node->left; - succ->right = node->right; - succ->color = node->color; - - parent = node->parent; - if (parent != null) { - if (parent->left==node) - parent->left=succ; - else - parent->right=succ; - } - if (node->left != null) - node->left->parent = succ;; - if (node->right != null) - node->right->parent = succ; - - if (tree->root == node) - tree->root = succ; - } - - if (succ->color == PJ_RBCOLOR_BLACK) { - if (child != null) - delete_fixup(tree, child); - tree->null->color = PJ_RBCOLOR_BLACK; - } - - --tree->size; - return node; -} - - -PJ_DEF(unsigned) pj_rbtree_max_height( pj_rbtree *tree, - pj_rbtree_node *node ) -{ - unsigned l, r; - - PJ_CHECK_STACK(); - - if (node==NULL) - node = tree->root; - - l = node->left != tree->null ? pj_rbtree_max_height(tree,node->left)+1 : 0; - r = node->right != tree->null ? pj_rbtree_max_height(tree,node->right)+1 : 0; - return l > r ? l : r; -} - -PJ_DEF(unsigned) pj_rbtree_min_height( pj_rbtree *tree, - pj_rbtree_node *node ) -{ - unsigned l, r; - - PJ_CHECK_STACK(); - - if (node==NULL) - node=tree->root; - - l = (node->left != tree->null) ? pj_rbtree_max_height(tree,node->left)+1 : 0; - r = (node->right != tree->null) ? pj_rbtree_max_height(tree,node->right)+1 : 0; - return l > r ? r : l; -} - - +/* $Header: /pjproject-0.3/pjlib/src/pj/rbtree.c 5 9/17/05 10:37a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/rbtree.c $ + * + * 5 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include + +static void left_rotate( pj_rbtree *tree, pj_rbtree_node *node ) +{ + pj_rbtree_node *rnode, *parent; + + PJ_CHECK_STACK(); + + rnode = node->right; + if (rnode == tree->null) + return; + + node->right = rnode->left; + if (rnode->left != tree->null) + rnode->left->parent = node; + parent = node->parent; + rnode->parent = parent; + if (parent != tree->null) { + if (parent->left == node) + parent->left = rnode; + else + parent->right = rnode; + } else { + tree->root = rnode; + } + rnode->left = node; + node->parent = rnode; +} + +static void right_rotate( pj_rbtree *tree, pj_rbtree_node *node ) +{ + pj_rbtree_node *lnode, *parent; + + PJ_CHECK_STACK(); + + lnode = node->left; + if (lnode == tree->null) + return; + + node->left = lnode->right; + if (lnode->right != tree->null) + lnode->right->parent = node; + parent = node->parent; + lnode->parent = parent; + + if (parent != tree->null) { + if (parent->left == node) + parent->left = lnode; + else + parent->right = lnode; + } else { + tree->root = lnode; + } + lnode->right = node; + node->parent = lnode; +} + +static void insert_fixup( pj_rbtree *tree, pj_rbtree_node *node ) +{ + pj_rbtree_node *temp, *parent; + + PJ_CHECK_STACK(); + + while (node != tree->root && node->parent->color == PJ_RBCOLOR_RED) { + parent = node->parent; + if (parent == parent->parent->left) { + temp = parent->parent->right; + if (temp->color == PJ_RBCOLOR_RED) { + temp->color = PJ_RBCOLOR_BLACK; + node = parent; + node->color = PJ_RBCOLOR_BLACK; + node = node->parent; + node->color = PJ_RBCOLOR_RED; + } else { + if (node == parent->right) { + node = parent; + left_rotate(tree, node); + } + temp = node->parent; + temp->color = PJ_RBCOLOR_BLACK; + temp = temp->parent; + temp->color = PJ_RBCOLOR_RED; + right_rotate( tree, temp); + } + } else { + temp = parent->parent->left; + if (temp->color == PJ_RBCOLOR_RED) { + temp->color = PJ_RBCOLOR_BLACK; + node = parent; + node->color = PJ_RBCOLOR_BLACK; + node = node->parent; + node->color = PJ_RBCOLOR_RED; + } else { + if (node == parent->left) { + node = parent; + right_rotate(tree, node); + } + temp = node->parent; + temp->color = PJ_RBCOLOR_BLACK; + temp = temp->parent; + temp->color = PJ_RBCOLOR_RED; + left_rotate(tree, temp); + } + } + } + + tree->root->color = PJ_RBCOLOR_BLACK; +} + + +static void delete_fixup( pj_rbtree *tree, pj_rbtree_node *node ) +{ + pj_rbtree_node *temp; + + PJ_CHECK_STACK(); + + while (node != tree->root && node->color == PJ_RBCOLOR_BLACK) { + if (node->parent->left == node) { + temp = node->parent->right; + if (temp->color == PJ_RBCOLOR_RED) { + temp->color = PJ_RBCOLOR_BLACK; + node->parent->color = PJ_RBCOLOR_RED; + left_rotate(tree, node->parent); + temp = node->parent->right; + } + if (temp->left->color == PJ_RBCOLOR_BLACK && + temp->right->color == PJ_RBCOLOR_BLACK) + { + temp->color = PJ_RBCOLOR_RED; + node = node->parent; + } else { + if (temp->right->color == PJ_RBCOLOR_BLACK) { + temp->left->color = PJ_RBCOLOR_BLACK; + temp->color = PJ_RBCOLOR_RED; + right_rotate( tree, temp); + temp = node->parent->right; + } + temp->color = node->parent->color; + temp->right->color = PJ_RBCOLOR_BLACK; + node->parent->color = PJ_RBCOLOR_BLACK; + left_rotate(tree, node->parent); + node = tree->root; + } + } else { + temp = node->parent->left; + if (temp->color == PJ_RBCOLOR_RED) { + temp->color = PJ_RBCOLOR_BLACK; + node->parent->color = PJ_RBCOLOR_RED; + right_rotate( tree, node->parent); + temp = node->parent->left; + } + if (temp->right->color == PJ_RBCOLOR_BLACK && + temp->left->color == PJ_RBCOLOR_BLACK) + { + temp->color = PJ_RBCOLOR_RED; + node = node->parent; + } else { + if (temp->left->color == PJ_RBCOLOR_BLACK) { + temp->right->color = PJ_RBCOLOR_BLACK; + temp->color = PJ_RBCOLOR_RED; + left_rotate( tree, temp); + temp = node->parent->left; + } + temp->color = node->parent->color; + node->parent->color = PJ_RBCOLOR_BLACK; + temp->left->color = PJ_RBCOLOR_BLACK; + right_rotate(tree, node->parent); + node = tree->root; + } + } + } + + node->color = PJ_RBCOLOR_BLACK; +} + + +PJ_DEF(void) pj_rbtree_init( pj_rbtree *tree, pj_rbtree_comp *comp ) +{ + PJ_CHECK_STACK(); + + tree->null = tree->root = &tree->null_node; + tree->null->key = NULL; + tree->null->user_data = NULL; + tree->size = 0; + tree->null->left = tree->null->right = tree->null->parent = tree->null; + tree->null->color = PJ_RBCOLOR_BLACK; + tree->comp = comp; +} + +PJ_DEF(pj_rbtree_node*) pj_rbtree_first( pj_rbtree *tree ) +{ + register pj_rbtree_node *node = tree->root; + register pj_rbtree_node *null = tree->null; + + PJ_CHECK_STACK(); + + while (node->left != null) + node = node->left; + return node != null ? node : NULL; +} + +PJ_DEF(pj_rbtree_node*) pj_rbtree_last( pj_rbtree *tree ) +{ + register pj_rbtree_node *node = tree->root; + register pj_rbtree_node *null = tree->null; + + PJ_CHECK_STACK(); + + while (node->right != null) + node = node->right; + return node != null ? node : NULL; +} + +PJ_DEF(pj_rbtree_node*) pj_rbtree_next( pj_rbtree *tree, + register pj_rbtree_node *node ) +{ + register pj_rbtree_node *null = tree->null; + + PJ_CHECK_STACK(); + + if (node->right != null) { + for (node=node->right; node->left!=null; node = node->left) + /* void */; + } else { + register pj_rbtree_node *temp = node->parent; + while (temp!=null && temp->right==node) { + node = temp; + temp = temp->parent; + } + node = temp; + } + return node != null ? node : NULL; +} + +PJ_DEF(pj_rbtree_node*) pj_rbtree_prev( pj_rbtree *tree, + register pj_rbtree_node *node ) +{ + register pj_rbtree_node *null = tree->null; + + PJ_CHECK_STACK(); + + if (node->left != null) { + for (node=node->left; node->right!=null; node=node->right) + /* void */; + } else { + register pj_rbtree_node *temp = node->parent; + while (temp!=null && temp->left==node) { + node = temp; + temp = temp->parent; + } + node = temp; + } + return node != null ? node : NULL; +} + +PJ_DEF(int) pj_rbtree_insert( pj_rbtree *tree, + pj_rbtree_node *element ) +{ + int rv = 0; + pj_rbtree_node *node, *parent = tree->null, + *null = tree->null; + pj_rbtree_comp *comp = tree->comp; + + PJ_CHECK_STACK(); + + node = tree->root; + while (node != null) { + rv = (*comp)(element->key, node->key); + if (rv == 0) { + /* found match, i.e. entry with equal key already exist */ + return -1; + } + parent = node; + node = rv < 0 ? node->left : node->right; + } + + element->color = PJ_RBCOLOR_RED; + element->left = element->right = null; + + node = element; + if (parent != null) { + node->parent = parent; + if (rv < 0) + parent->left = node; + else + parent->right = node; + insert_fixup( tree, node); + } else { + tree->root = node; + node->parent = null; + node->color = PJ_RBCOLOR_BLACK; + } + + ++tree->size; + return 0; +} + + +PJ_DEF(pj_rbtree_node*) pj_rbtree_find( pj_rbtree *tree, + const void *key ) +{ + int rv; + pj_rbtree_node *node = tree->root; + pj_rbtree_node *null = tree->null; + pj_rbtree_comp *comp = tree->comp; + + while (node != null) { + rv = (*comp)(key, node->key); + if (rv == 0) + return node; + node = rv < 0 ? node->left : node->right; + } + return node != null ? node : NULL; +} + +PJ_DEF(pj_rbtree_node*) pj_rbtree_erase( pj_rbtree *tree, + pj_rbtree_node *node ) +{ + pj_rbtree_node *succ; + pj_rbtree_node *null = tree->null; + pj_rbtree_node *child; + pj_rbtree_node *parent; + + PJ_CHECK_STACK(); + + if (node->left == null || node->right == null) { + succ = node; + } else { + for (succ=node->right; succ->left!=null; succ=succ->left) + /* void */; + } + + child = succ->left != null ? succ->left : succ->right; + parent = succ->parent; + child->parent = parent; + + if (parent != null) { + if (parent->left == succ) + parent->left = child; + else + parent->right = child; + } else + tree->root = child; + + if (succ != node) { + succ->parent = node->parent; + succ->left = node->left; + succ->right = node->right; + succ->color = node->color; + + parent = node->parent; + if (parent != null) { + if (parent->left==node) + parent->left=succ; + else + parent->right=succ; + } + if (node->left != null) + node->left->parent = succ;; + if (node->right != null) + node->right->parent = succ; + + if (tree->root == node) + tree->root = succ; + } + + if (succ->color == PJ_RBCOLOR_BLACK) { + if (child != null) + delete_fixup(tree, child); + tree->null->color = PJ_RBCOLOR_BLACK; + } + + --tree->size; + return node; +} + + +PJ_DEF(unsigned) pj_rbtree_max_height( pj_rbtree *tree, + pj_rbtree_node *node ) +{ + unsigned l, r; + + PJ_CHECK_STACK(); + + if (node==NULL) + node = tree->root; + + l = node->left != tree->null ? pj_rbtree_max_height(tree,node->left)+1 : 0; + r = node->right != tree->null ? pj_rbtree_max_height(tree,node->right)+1 : 0; + return l > r ? l : r; +} + +PJ_DEF(unsigned) pj_rbtree_min_height( pj_rbtree *tree, + pj_rbtree_node *node ) +{ + unsigned l, r; + + PJ_CHECK_STACK(); + + if (node==NULL) + node=tree->root; + + l = (node->left != tree->null) ? pj_rbtree_max_height(tree,node->left)+1 : 0; + r = (node->right != tree->null) ? pj_rbtree_max_height(tree,node->right)+1 : 0; + return l > r ? r : l; +} + + diff --git a/pjlib/src/pj/scanner.c b/pjlib/src/pj/scanner.c index 08c7c757..b8296cba 100644 --- a/pjlib/src/pj/scanner.c +++ b/pjlib/src/pj/scanner.c @@ -1,556 +1,556 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/scanner.c 9 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/scanner.c $ - * - * 9 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 8 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 7 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include -#include - -#define PJ_SCAN_IS_SPACE(c) ((c)==' ' || (c)=='\t') -#define PJ_SCAN_IS_NEWLINE(c) ((c)=='\r' || (c)=='\n') -#define PJ_SCAN_CHECK_EOF(s) (s != end) - - -static void pj_scan_syntax_err(pj_scanner *scanner) -{ - (*scanner->callback)(scanner); -} - -PJ_DEF(void) pj_cs_init( pj_char_spec cs) -{ - PJ_CHECK_STACK(); - memset(cs, 0, sizeof(cs)); -} - -PJ_DEF(void) pj_cs_set( pj_char_spec cs, int c) -{ - PJ_CHECK_STACK(); - cs[c] = 1; -} - -PJ_DEF(void) pj_cs_add_range( pj_char_spec cs, int cstart, int cend) -{ - PJ_CHECK_STACK(); - while (cstart != cend) - cs[cstart++] = 1; -} - -PJ_DEF(void) pj_cs_add_alpha( pj_char_spec cs) -{ - pj_cs_add_range( cs, 'a', 'z'+1); - pj_cs_add_range( cs, 'A', 'Z'+1); -} - -PJ_DEF(void) pj_cs_add_num( pj_char_spec cs) -{ - pj_cs_add_range( cs, '0', '9'+1); -} - -PJ_DEF(void) pj_cs_add_str( pj_char_spec cs, const char *str) -{ - PJ_CHECK_STACK(); - while (*str) { - cs[(int)*str] = 1; - ++str; - } -} - -PJ_DEF(void) pj_cs_del_range( pj_char_spec cs, int cstart, int cend) -{ - PJ_CHECK_STACK(); - while (cstart != cend) - cs[cstart++] = 0; -} - -PJ_DEF(void) pj_cs_del_str( pj_char_spec cs, const char *str) -{ - PJ_CHECK_STACK(); - while (*str) { - cs[(int)*str] = 0; - ++str; - } -} - -PJ_DEF(void) pj_cs_invert( pj_char_spec cs ) -{ - unsigned i; - PJ_CHECK_STACK(); - for (i=0; ibegin = scanner->curptr = bufstart; - scanner->end = bufstart + buflen; - scanner->line = 1; - scanner->col = 1; - scanner->callback = callback; - scanner->skip_ws = options; - - if (scanner->skip_ws) - pj_scan_skip_whitespace(scanner); - - scanner->col = scanner->curptr - scanner->begin + 1; -} - - -PJ_DEF(void) pj_scan_fini( pj_scanner *scanner ) -{ - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(scanner); -} - -PJ_DEF(void) pj_scan_skip_whitespace( pj_scanner *scanner ) -{ - register char *s = scanner->curptr; - - PJ_CHECK_STACK(); - - while (PJ_SCAN_IS_SPACE(*s)) { - ++s; - } - - if ((scanner->skip_ws & PJ_SCAN_AUTOSKIP_NEWLINE) && PJ_SCAN_IS_NEWLINE(*s)) { - for (;;) { - if (*s == '\r') { - ++s; - if (*s == '\n') ++s; - ++scanner->line; - scanner->col = 1; - scanner->curptr = s; - } else if (*s == '\n') { - ++s; - ++scanner->line; - scanner->col = 1; - scanner->curptr = s; - } else if (PJ_SCAN_IS_SPACE(*s)) { - do { - ++s; - } while (PJ_SCAN_IS_SPACE(*s)); - } else { - break; - } - } - } - - if (PJ_SCAN_IS_NEWLINE(*s) && (scanner->skip_ws & PJ_SCAN_AUTOSKIP_WS_HEADER)==PJ_SCAN_AUTOSKIP_WS_HEADER) { - /* Check for header continuation. */ - scanner->col += s - scanner->curptr; - scanner->curptr = s; - - if (*s == '\r') { - ++s; - } - if (*s == '\n') { - ++s; - } - if (PJ_SCAN_IS_SPACE(*s)) { - register char *t = s; - do { - ++t; - } while (PJ_SCAN_IS_SPACE(*t)); - - ++scanner->line; - scanner->col = t-s; - scanner->curptr = t; - } - } else { - scanner->col += s - scanner->curptr; - scanner->curptr = s; - } -} - -PJ_DEF(int) pj_scan_peek( pj_scanner *scanner, - const pj_char_spec spec, pj_str_t *out) -{ - register char *s = scanner->curptr; - register char *end = scanner->end; - - PJ_CHECK_STACK(); - - if (pj_scan_is_eof(scanner)) { - pj_scan_syntax_err(scanner); - return -1; - } - - while (PJ_SCAN_CHECK_EOF(s) && pj_cs_match(spec, *s)) - ++s; - - pj_strset3(out, scanner->curptr, s); - return s < scanner->end ? *s : 0; -} - - -PJ_DEF(int) pj_scan_peek_n( pj_scanner *scanner, - pj_size_t len, pj_str_t *out) -{ - char *endpos = scanner->curptr + len; - - PJ_CHECK_STACK(); - - if (endpos > scanner->end) { - pj_scan_syntax_err(scanner); - return -1; - } - - pj_strset(out, scanner->curptr, len); - return *endpos; -} - - -PJ_DEF(int) pj_scan_peek_until( pj_scanner *scanner, - const pj_char_spec spec, - pj_str_t *out) -{ - register char *s = scanner->curptr; - register char *end = scanner->end; - - PJ_CHECK_STACK(); - - if (pj_scan_is_eof(scanner)) { - pj_scan_syntax_err(scanner); - return -1; - } - - while (PJ_SCAN_CHECK_EOF(s) && !pj_cs_match( spec, *s)) - ++s; - - pj_strset3(out, scanner->curptr, s); - return s!=scanner->end ? *s : 0; -} - - -PJ_DEF(void) pj_scan_get( pj_scanner *scanner, - const pj_char_spec spec, pj_str_t *out) -{ - register char *s = scanner->curptr; - register char *end = scanner->end; - char *start = s; - - PJ_CHECK_STACK(); - - if (pj_scan_is_eof(scanner) || !pj_cs_match(spec, *s)) { - pj_scan_syntax_err(scanner); - return; - } - - do { - ++s; - } while (PJ_SCAN_CHECK_EOF(s) && pj_cs_match(spec, *s)); - - pj_strset3(out, scanner->curptr, s); - - scanner->col += (s - start); - scanner->curptr = s; - - if (scanner->skip_ws) { - pj_scan_skip_whitespace(scanner); - } -} - - -PJ_DEF(void) pj_scan_get_quote( pj_scanner *scanner, - int begin_quote, int end_quote, - pj_str_t *out) -{ - register char *s = scanner->curptr; - register char *end = scanner->end; - char *start = s; - - PJ_CHECK_STACK(); - - /* Check and eat the begin_quote. */ - if (*s != begin_quote) { - pj_scan_syntax_err(scanner); - return; - } - ++s; - - /* Loop until end_quote is found. - */ - do { - /* loop until end_quote is found. */ - do { - ++s; - } while (s != end && *s != '\n' && *s != end_quote); - - /* check that no backslash character precedes the end_quote. */ - if (*s == end_quote) { - if (*(s-1) == '\\') { - if (s-2 == scanner->begin) { - break; - } else { - char *q = s-2; - char *r = s-2; - - while (r != scanner->begin && *r == '\\') { - --r; - } - /* break from main loop if we have odd number of backslashes */ - if (((unsigned)(q-r) & 0x01) == 1) { - break; - } - } - } else { - /* end_quote is not preceeded by backslash. break now. */ - break; - } - } else { - /* loop ended by non-end_quote character. break now. */ - break; - } - } while (1); - - /* Check and eat the end quote. */ - if (*s != end_quote) { - pj_scan_syntax_err(scanner); - return; - } - ++s; - - pj_strset3(out, scanner->curptr, s); - - scanner->col += (s - start); - scanner->curptr = s; - - if (scanner->skip_ws) { - pj_scan_skip_whitespace(scanner); - } -} - -PJ_DEF(void) pj_scan_get_n( pj_scanner *scanner, - unsigned N, pj_str_t *out) -{ - register char *s = scanner->curptr; - char *start = scanner->curptr; - - PJ_CHECK_STACK(); - - if (scanner->curptr + N > scanner->end) { - pj_scan_syntax_err(scanner); - return; - } - - pj_strset(out, s, N); - - s += N; - scanner->col += (s - start); - scanner->curptr = s; - - if (scanner->skip_ws) { - pj_scan_skip_whitespace(scanner); - } -} - - -PJ_DEF(int) pj_scan_get_char( pj_scanner *scanner ) -{ - char *start = scanner->curptr; - int chr = *start; - - PJ_CHECK_STACK(); - - if (pj_scan_is_eof(scanner)) { - pj_scan_syntax_err(scanner); - return 0; - } - - ++scanner->curptr; - scanner->col += (scanner->curptr - start); - - if (scanner->skip_ws) { - pj_scan_skip_whitespace(scanner); - } - return chr; -} - - -PJ_DEF(void) pj_scan_get_newline( pj_scanner *scanner ) -{ - PJ_CHECK_STACK(); - - if (!PJ_SCAN_IS_NEWLINE(*scanner->curptr)) { - pj_scan_syntax_err(scanner); - return; - } - - if (*scanner->curptr == '\r') { - ++scanner->curptr; - } - if (*scanner->curptr == '\n') { - ++scanner->curptr; - } - - ++scanner->line; - scanner->col = 1; - - if (scanner->skip_ws) { - pj_scan_skip_whitespace(scanner); - } -} - - -PJ_DEF(void) pj_scan_get_until( pj_scanner *scanner, - const pj_char_spec spec, pj_str_t *out) -{ - register char *s = scanner->curptr; - register char *end = scanner->end; - char *start = s; - - PJ_CHECK_STACK(); - - if (pj_scan_is_eof(scanner)) { - pj_scan_syntax_err(scanner); - return; - } - - while (PJ_SCAN_CHECK_EOF(s) && !pj_cs_match(spec, *s)) { - ++s; - } - - pj_strset3(out, scanner->curptr, s); - - scanner->col += (s - start); - scanner->curptr = s; - - if (scanner->skip_ws) { - pj_scan_skip_whitespace(scanner); - } -} - - -PJ_DEF(void) pj_scan_get_until_ch( pj_scanner *scanner, - int until_char, pj_str_t *out) -{ - register char *s = scanner->curptr; - register char *end = scanner->end; - char *start = s; - - PJ_CHECK_STACK(); - - if (pj_scan_is_eof(scanner)) { - pj_scan_syntax_err(scanner); - return; - } - - while (PJ_SCAN_CHECK_EOF(s) && *s != until_char) { - ++s; - } - - pj_strset3(out, scanner->curptr, s); - - scanner->col += (s - start); - scanner->curptr = s; - - if (scanner->skip_ws) { - pj_scan_skip_whitespace(scanner); - } -} - - -PJ_DEF(void) pj_scan_get_until_chr( pj_scanner *scanner, - const char *until_spec, pj_str_t *out) -{ - register char *s = scanner->curptr; - register char *end = scanner->end; - char *start = scanner->curptr; - - PJ_CHECK_STACK(); - - if (pj_scan_is_eof(scanner)) { - pj_scan_syntax_err(scanner); - return; - } - - while (PJ_SCAN_CHECK_EOF(s) && !strchr(until_spec, *s)) { - ++s; - } - - pj_strset3(out, scanner->curptr, s); - - scanner->col += (s - start); - scanner->curptr = s; - - if (scanner->skip_ws) { - pj_scan_skip_whitespace(scanner); - } -} - -PJ_DEF(void) pj_scan_advance_n( pj_scanner *scanner, - unsigned N, pj_bool_t skip_ws) -{ - char *start = scanner->curptr; - - PJ_CHECK_STACK(); - - if (scanner->curptr + N > scanner->end) { - pj_scan_syntax_err(scanner); - return; - } - - scanner->curptr += N; - scanner->col += (scanner->curptr - start); - - if (skip_ws) { - pj_scan_skip_whitespace(scanner); - } -} - - -PJ_DEF(int) pj_scan_strcmp( pj_scanner *scanner, const char *s, int len) -{ - if (scanner->curptr + len > scanner->end) { - pj_scan_syntax_err(scanner); - return -1; - } - return strncmp(scanner->curptr, s, len); -} - - -PJ_DEF(int) pj_scan_stricmp( pj_scanner *scanner, const char *s, int len) -{ - if (scanner->curptr + len > scanner->end) { - pj_scan_syntax_err(scanner); - return -1; - } - return strnicmp(scanner->curptr, s, len); -} - - -PJ_DEF(void) pj_scan_save_state( pj_scanner *scanner, pj_scan_state *state) -{ - PJ_CHECK_STACK(); - - state->curptr = scanner->curptr; - state->line = scanner->line; - state->col = scanner->col; -} - - -PJ_DEF(void) pj_scan_restore_state( pj_scanner *scanner, - pj_scan_state *state) -{ - PJ_CHECK_STACK(); - - scanner->curptr = state->curptr; - scanner->line = state->line; - scanner->col = state->col; -} - - +/* $Header: /pjproject-0.3/pjlib/src/pj/scanner.c 9 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/scanner.c $ + * + * 9 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 8 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 7 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include +#include +#include + +#define PJ_SCAN_IS_SPACE(c) ((c)==' ' || (c)=='\t') +#define PJ_SCAN_IS_NEWLINE(c) ((c)=='\r' || (c)=='\n') +#define PJ_SCAN_CHECK_EOF(s) (s != end) + + +static void pj_scan_syntax_err(pj_scanner *scanner) +{ + (*scanner->callback)(scanner); +} + +PJ_DEF(void) pj_cs_init( pj_char_spec cs) +{ + PJ_CHECK_STACK(); + memset(cs, 0, sizeof(cs)); +} + +PJ_DEF(void) pj_cs_set( pj_char_spec cs, int c) +{ + PJ_CHECK_STACK(); + cs[c] = 1; +} + +PJ_DEF(void) pj_cs_add_range( pj_char_spec cs, int cstart, int cend) +{ + PJ_CHECK_STACK(); + while (cstart != cend) + cs[cstart++] = 1; +} + +PJ_DEF(void) pj_cs_add_alpha( pj_char_spec cs) +{ + pj_cs_add_range( cs, 'a', 'z'+1); + pj_cs_add_range( cs, 'A', 'Z'+1); +} + +PJ_DEF(void) pj_cs_add_num( pj_char_spec cs) +{ + pj_cs_add_range( cs, '0', '9'+1); +} + +PJ_DEF(void) pj_cs_add_str( pj_char_spec cs, const char *str) +{ + PJ_CHECK_STACK(); + while (*str) { + cs[(int)*str] = 1; + ++str; + } +} + +PJ_DEF(void) pj_cs_del_range( pj_char_spec cs, int cstart, int cend) +{ + PJ_CHECK_STACK(); + while (cstart != cend) + cs[cstart++] = 0; +} + +PJ_DEF(void) pj_cs_del_str( pj_char_spec cs, const char *str) +{ + PJ_CHECK_STACK(); + while (*str) { + cs[(int)*str] = 0; + ++str; + } +} + +PJ_DEF(void) pj_cs_invert( pj_char_spec cs ) +{ + unsigned i; + PJ_CHECK_STACK(); + for (i=0; ibegin = scanner->curptr = bufstart; + scanner->end = bufstart + buflen; + scanner->line = 1; + scanner->col = 1; + scanner->callback = callback; + scanner->skip_ws = options; + + if (scanner->skip_ws) + pj_scan_skip_whitespace(scanner); + + scanner->col = scanner->curptr - scanner->begin + 1; +} + + +PJ_DEF(void) pj_scan_fini( pj_scanner *scanner ) +{ + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(scanner); +} + +PJ_DEF(void) pj_scan_skip_whitespace( pj_scanner *scanner ) +{ + register char *s = scanner->curptr; + + PJ_CHECK_STACK(); + + while (PJ_SCAN_IS_SPACE(*s)) { + ++s; + } + + if ((scanner->skip_ws & PJ_SCAN_AUTOSKIP_NEWLINE) && PJ_SCAN_IS_NEWLINE(*s)) { + for (;;) { + if (*s == '\r') { + ++s; + if (*s == '\n') ++s; + ++scanner->line; + scanner->col = 1; + scanner->curptr = s; + } else if (*s == '\n') { + ++s; + ++scanner->line; + scanner->col = 1; + scanner->curptr = s; + } else if (PJ_SCAN_IS_SPACE(*s)) { + do { + ++s; + } while (PJ_SCAN_IS_SPACE(*s)); + } else { + break; + } + } + } + + if (PJ_SCAN_IS_NEWLINE(*s) && (scanner->skip_ws & PJ_SCAN_AUTOSKIP_WS_HEADER)==PJ_SCAN_AUTOSKIP_WS_HEADER) { + /* Check for header continuation. */ + scanner->col += s - scanner->curptr; + scanner->curptr = s; + + if (*s == '\r') { + ++s; + } + if (*s == '\n') { + ++s; + } + if (PJ_SCAN_IS_SPACE(*s)) { + register char *t = s; + do { + ++t; + } while (PJ_SCAN_IS_SPACE(*t)); + + ++scanner->line; + scanner->col = t-s; + scanner->curptr = t; + } + } else { + scanner->col += s - scanner->curptr; + scanner->curptr = s; + } +} + +PJ_DEF(int) pj_scan_peek( pj_scanner *scanner, + const pj_char_spec spec, pj_str_t *out) +{ + register char *s = scanner->curptr; + register char *end = scanner->end; + + PJ_CHECK_STACK(); + + if (pj_scan_is_eof(scanner)) { + pj_scan_syntax_err(scanner); + return -1; + } + + while (PJ_SCAN_CHECK_EOF(s) && pj_cs_match(spec, *s)) + ++s; + + pj_strset3(out, scanner->curptr, s); + return s < scanner->end ? *s : 0; +} + + +PJ_DEF(int) pj_scan_peek_n( pj_scanner *scanner, + pj_size_t len, pj_str_t *out) +{ + char *endpos = scanner->curptr + len; + + PJ_CHECK_STACK(); + + if (endpos > scanner->end) { + pj_scan_syntax_err(scanner); + return -1; + } + + pj_strset(out, scanner->curptr, len); + return *endpos; +} + + +PJ_DEF(int) pj_scan_peek_until( pj_scanner *scanner, + const pj_char_spec spec, + pj_str_t *out) +{ + register char *s = scanner->curptr; + register char *end = scanner->end; + + PJ_CHECK_STACK(); + + if (pj_scan_is_eof(scanner)) { + pj_scan_syntax_err(scanner); + return -1; + } + + while (PJ_SCAN_CHECK_EOF(s) && !pj_cs_match( spec, *s)) + ++s; + + pj_strset3(out, scanner->curptr, s); + return s!=scanner->end ? *s : 0; +} + + +PJ_DEF(void) pj_scan_get( pj_scanner *scanner, + const pj_char_spec spec, pj_str_t *out) +{ + register char *s = scanner->curptr; + register char *end = scanner->end; + char *start = s; + + PJ_CHECK_STACK(); + + if (pj_scan_is_eof(scanner) || !pj_cs_match(spec, *s)) { + pj_scan_syntax_err(scanner); + return; + } + + do { + ++s; + } while (PJ_SCAN_CHECK_EOF(s) && pj_cs_match(spec, *s)); + + pj_strset3(out, scanner->curptr, s); + + scanner->col += (s - start); + scanner->curptr = s; + + if (scanner->skip_ws) { + pj_scan_skip_whitespace(scanner); + } +} + + +PJ_DEF(void) pj_scan_get_quote( pj_scanner *scanner, + int begin_quote, int end_quote, + pj_str_t *out) +{ + register char *s = scanner->curptr; + register char *end = scanner->end; + char *start = s; + + PJ_CHECK_STACK(); + + /* Check and eat the begin_quote. */ + if (*s != begin_quote) { + pj_scan_syntax_err(scanner); + return; + } + ++s; + + /* Loop until end_quote is found. + */ + do { + /* loop until end_quote is found. */ + do { + ++s; + } while (s != end && *s != '\n' && *s != end_quote); + + /* check that no backslash character precedes the end_quote. */ + if (*s == end_quote) { + if (*(s-1) == '\\') { + if (s-2 == scanner->begin) { + break; + } else { + char *q = s-2; + char *r = s-2; + + while (r != scanner->begin && *r == '\\') { + --r; + } + /* break from main loop if we have odd number of backslashes */ + if (((unsigned)(q-r) & 0x01) == 1) { + break; + } + } + } else { + /* end_quote is not preceeded by backslash. break now. */ + break; + } + } else { + /* loop ended by non-end_quote character. break now. */ + break; + } + } while (1); + + /* Check and eat the end quote. */ + if (*s != end_quote) { + pj_scan_syntax_err(scanner); + return; + } + ++s; + + pj_strset3(out, scanner->curptr, s); + + scanner->col += (s - start); + scanner->curptr = s; + + if (scanner->skip_ws) { + pj_scan_skip_whitespace(scanner); + } +} + +PJ_DEF(void) pj_scan_get_n( pj_scanner *scanner, + unsigned N, pj_str_t *out) +{ + register char *s = scanner->curptr; + char *start = scanner->curptr; + + PJ_CHECK_STACK(); + + if (scanner->curptr + N > scanner->end) { + pj_scan_syntax_err(scanner); + return; + } + + pj_strset(out, s, N); + + s += N; + scanner->col += (s - start); + scanner->curptr = s; + + if (scanner->skip_ws) { + pj_scan_skip_whitespace(scanner); + } +} + + +PJ_DEF(int) pj_scan_get_char( pj_scanner *scanner ) +{ + char *start = scanner->curptr; + int chr = *start; + + PJ_CHECK_STACK(); + + if (pj_scan_is_eof(scanner)) { + pj_scan_syntax_err(scanner); + return 0; + } + + ++scanner->curptr; + scanner->col += (scanner->curptr - start); + + if (scanner->skip_ws) { + pj_scan_skip_whitespace(scanner); + } + return chr; +} + + +PJ_DEF(void) pj_scan_get_newline( pj_scanner *scanner ) +{ + PJ_CHECK_STACK(); + + if (!PJ_SCAN_IS_NEWLINE(*scanner->curptr)) { + pj_scan_syntax_err(scanner); + return; + } + + if (*scanner->curptr == '\r') { + ++scanner->curptr; + } + if (*scanner->curptr == '\n') { + ++scanner->curptr; + } + + ++scanner->line; + scanner->col = 1; + + if (scanner->skip_ws) { + pj_scan_skip_whitespace(scanner); + } +} + + +PJ_DEF(void) pj_scan_get_until( pj_scanner *scanner, + const pj_char_spec spec, pj_str_t *out) +{ + register char *s = scanner->curptr; + register char *end = scanner->end; + char *start = s; + + PJ_CHECK_STACK(); + + if (pj_scan_is_eof(scanner)) { + pj_scan_syntax_err(scanner); + return; + } + + while (PJ_SCAN_CHECK_EOF(s) && !pj_cs_match(spec, *s)) { + ++s; + } + + pj_strset3(out, scanner->curptr, s); + + scanner->col += (s - start); + scanner->curptr = s; + + if (scanner->skip_ws) { + pj_scan_skip_whitespace(scanner); + } +} + + +PJ_DEF(void) pj_scan_get_until_ch( pj_scanner *scanner, + int until_char, pj_str_t *out) +{ + register char *s = scanner->curptr; + register char *end = scanner->end; + char *start = s; + + PJ_CHECK_STACK(); + + if (pj_scan_is_eof(scanner)) { + pj_scan_syntax_err(scanner); + return; + } + + while (PJ_SCAN_CHECK_EOF(s) && *s != until_char) { + ++s; + } + + pj_strset3(out, scanner->curptr, s); + + scanner->col += (s - start); + scanner->curptr = s; + + if (scanner->skip_ws) { + pj_scan_skip_whitespace(scanner); + } +} + + +PJ_DEF(void) pj_scan_get_until_chr( pj_scanner *scanner, + const char *until_spec, pj_str_t *out) +{ + register char *s = scanner->curptr; + register char *end = scanner->end; + char *start = scanner->curptr; + + PJ_CHECK_STACK(); + + if (pj_scan_is_eof(scanner)) { + pj_scan_syntax_err(scanner); + return; + } + + while (PJ_SCAN_CHECK_EOF(s) && !strchr(until_spec, *s)) { + ++s; + } + + pj_strset3(out, scanner->curptr, s); + + scanner->col += (s - start); + scanner->curptr = s; + + if (scanner->skip_ws) { + pj_scan_skip_whitespace(scanner); + } +} + +PJ_DEF(void) pj_scan_advance_n( pj_scanner *scanner, + unsigned N, pj_bool_t skip_ws) +{ + char *start = scanner->curptr; + + PJ_CHECK_STACK(); + + if (scanner->curptr + N > scanner->end) { + pj_scan_syntax_err(scanner); + return; + } + + scanner->curptr += N; + scanner->col += (scanner->curptr - start); + + if (skip_ws) { + pj_scan_skip_whitespace(scanner); + } +} + + +PJ_DEF(int) pj_scan_strcmp( pj_scanner *scanner, const char *s, int len) +{ + if (scanner->curptr + len > scanner->end) { + pj_scan_syntax_err(scanner); + return -1; + } + return strncmp(scanner->curptr, s, len); +} + + +PJ_DEF(int) pj_scan_stricmp( pj_scanner *scanner, const char *s, int len) +{ + if (scanner->curptr + len > scanner->end) { + pj_scan_syntax_err(scanner); + return -1; + } + return strnicmp(scanner->curptr, s, len); +} + + +PJ_DEF(void) pj_scan_save_state( pj_scanner *scanner, pj_scan_state *state) +{ + PJ_CHECK_STACK(); + + state->curptr = scanner->curptr; + state->line = scanner->line; + state->col = scanner->col; +} + + +PJ_DEF(void) pj_scan_restore_state( pj_scanner *scanner, + pj_scan_state *state) +{ + PJ_CHECK_STACK(); + + scanner->curptr = state->curptr; + scanner->line = state->line; + scanner->col = state->col; +} + + diff --git a/pjlib/src/pj/sock_bsd.c b/pjlib/src/pj/sock_bsd.c index c69b7e25..1465d487 100644 --- a/pjlib/src/pj/sock_bsd.c +++ b/pjlib/src/pj/sock_bsd.c @@ -1,572 +1,572 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/sock_bsd.c 10 10/29/05 11:51a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/sock_bsd.c $ - * - * 10 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 9 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 8 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 7 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include -#include -#include -#include -#include - -/* - * Address families conversion. - * The values here are indexed based on pj_addr_family-0xFF00. - */ -const pj_uint16_t PJ_AF_UNIX = AF_UNIX; -const pj_uint16_t PJ_AF_INET = AF_INET; -const pj_uint16_t PJ_AF_INET6 = AF_INET6; -#ifdef AF_PACKET -const pj_uint16_t PJ_AF_PACKET = AF_PACKET; -#else -const pj_uint16_t PJ_AF_PACKET = 0xFFFF; -#endif -#ifdef AF_IRDA -const pj_uint16_t PJ_AF_IRDA = AF_IRDA; -#else -const pj_uint16_t PJ_AF_IRDA = 0xFFFF; -#endif - -/* - * Socket types conversion. - * The values here are indexed based on pj_sock_type-0xFF00 - */ -const pj_uint16_t PJ_SOCK_STREAM = SOCK_STREAM; -const pj_uint16_t PJ_SOCK_DGRAM = SOCK_DGRAM; -const pj_uint16_t PJ_SOCK_RAW = SOCK_RAW; -const pj_uint16_t PJ_SOCK_RDM = SOCK_RDM; - -/* - * Socket level values. - */ -const pj_uint16_t PJ_SOL_SOCKET = SOL_SOCKET; -#ifdef SOL_IP -const pj_uint16_t PJ_SOL_IP = SOL_IP; -#else -const pj_uint16_t PJ_SOL_IP = 0xFFFF; -#endif /* SOL_IP */ -#if defined(SOL_TCP) -const pj_uint16_t PJ_SOL_TCP = SOL_TCP; -#elif defined(IPPROTO_TCP) -const pj_uint16_t PJ_SOL_TCP = IPPROTO_TCP; -#endif /* SOL_TCP */ -#ifdef SOL_UDP -const pj_uint16_t PJ_SOL_UDP = SOL_UDP; -#else -const pj_uint16_t PJ_SOL_UDP = 0xFFFF; -#endif -#ifdef SOL_IPV6 -const pj_uint16_t PJ_SOL_IPV6 = SOL_IPV6; -#else -const pj_uint16_t PJ_SOL_IPV6 = 0xFFFF; -#endif - - -/* - * Convert 16-bit value from network byte order to host byte order. - */ -PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort) -{ - return ntohs(netshort); -} - -/* - * Convert 16-bit value from host byte order to network byte order. - */ -PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort) -{ - return htons(hostshort); -} - -/* - * Convert 32-bit value from network byte order to host byte order. - */ -PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong) -{ - return ntohl(netlong); -} - -/* - * Convert 32-bit value from host byte order to network byte order. - */ -PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong) -{ - return htonl(hostlong); -} - -/* - * Convert an Internet host address given in network byte order - * to string in standard numbers and dots notation. - */ -PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr) -{ - return inet_ntoa(*(struct in_addr*)&inaddr); -} - -/* - * This function converts the Internet host address cp from the standard - * numbers-and-dots notation into binary data and stores it in the structure - * that inp points to. - */ -PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp) -{ - char tempaddr[16]; - - /* Initialize output with PJ_INADDR_NONE. - * Some apps relies on this instead of the return value - * (and anyway the return value is quite confusing!) - */ - inp->s_addr = PJ_INADDR_NONE; - - /* Caution: - * this function might be called with cp->slen >= 16 - * (i.e. when called with hostname to check if it's an IP addr). - */ - PJ_ASSERT_RETURN(cp && cp->slen && inp, 0); - if (cp->slen >= 16) { - return 0; - } - - pj_memcpy(tempaddr, cp->ptr, cp->slen); - tempaddr[cp->slen] = '\0'; - -#if defined(PJ_SOCK_HAS_INET_ATON) && PJ_SOCK_HAS_INET_ATON != 0 - return inet_aton(tempaddr, (struct in_addr*)inp); -#else - inp->s_addr = inet_addr(tempaddr); - return inp->s_addr == PJ_INADDR_NONE ? 0 : 1; -#endif -} - -/* - * Convert address string with numbers and dots to binary IP address. - */ -PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp) -{ - pj_in_addr addr; - - pj_inet_aton(cp, &addr); - return addr; -} - -/* - * Set the IP address of an IP socket address from string address, - * with resolving the host if necessary. The string address may be in a - * standard numbers and dots notation or may be a hostname. If hostname - * is specified, then the function will resolve the host into the IP - * address. - */ -PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr, - const pj_str_t *str_addr) -{ - PJ_CHECK_STACK(); - - PJ_ASSERT_RETURN(str_addr && str_addr->slen < PJ_MAX_HOSTNAME, - (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL)); - - addr->sin_family = AF_INET; - - if (str_addr && str_addr->slen) { - addr->sin_addr = pj_inet_addr(str_addr); - if (addr->sin_addr.s_addr == PJ_INADDR_NONE) { - pj_hostent he; - pj_status_t rc; - - rc = pj_gethostbyname(str_addr, &he); - if (rc == 0) { - addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr; - } else { - addr->sin_addr.s_addr = PJ_INADDR_NONE; - return rc; - } - } - - } else { - addr->sin_addr.s_addr = 0; - } - - return PJ_SUCCESS; -} - -/* - * Set the IP address and port of an IP socket address. - * The string address may be in a standard numbers and dots notation or - * may be a hostname. If hostname is specified, then the function will - * resolve the host into the IP address. - */ -PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr, - const pj_str_t *str_addr, - pj_uint16_t port) -{ - PJ_ASSERT_RETURN(addr && str_addr, - (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL)); - - addr->sin_family = PJ_AF_INET; - pj_sockaddr_in_set_port(addr, port); - return pj_sockaddr_in_set_str_addr(addr, str_addr); -} - - -/* - * Get hostname. - */ -PJ_DEF(const pj_str_t*) pj_gethostname(void) -{ - static char buf[PJ_MAX_HOSTNAME]; - static pj_str_t hostname; - - PJ_CHECK_STACK(); - - if (hostname.ptr == NULL) { - hostname.ptr = buf; - if (gethostname(buf, sizeof(buf)) != 0) { - hostname.ptr[0] = '\0'; - hostname.slen = 0; - } else { - hostname.slen = strlen(buf); - } - } - return &hostname; -} - -/* - * Get first IP address associated with the hostname. - */ -PJ_DEF(pj_in_addr) pj_gethostaddr(void) -{ - pj_sockaddr_in addr; - const pj_str_t *hostname = pj_gethostname(); - - pj_sockaddr_in_set_str_addr(&addr, hostname); - return addr.sin_addr; -} - - -#if defined(PJ_WIN32) -/* - * Create new socket/endpoint for communication and returns a descriptor. - */ -PJ_DEF(pj_status_t) pj_sock_socket(int af, - int type, - int proto, - pj_sock_t *sock) -{ - PJ_CHECK_STACK(); - - /* Sanity checks. */ - PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL); - PJ_ASSERT_RETURN((unsigned)PJ_INVALID_SOCKET==INVALID_SOCKET, - (*sock=PJ_INVALID_SOCKET, PJ_EINVAL)); - - *sock = WSASocket(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED); - - if (*sock == PJ_INVALID_SOCKET) - return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); - else - return PJ_SUCCESS; -} - -#else -/* - * Create new socket/endpoint for communication and returns a descriptor. - */ -PJ_DEF(pj_status_t) pj_sock_socket(int af, - int type, - int proto, - pj_sock_t *sock) -{ - - PJ_CHECK_STACK(); - - /* Sanity checks. */ - PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL); - PJ_ASSERT_RETURN(PJ_INVALID_SOCKET==-1, - (*sock=PJ_INVALID_SOCKET, PJ_EINVAL)); - - *sock = socket(af, type, proto); - if (*sock == PJ_INVALID_SOCKET) - return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); - else - return PJ_SUCCESS; -} -#endif - - -/* - * Bind socket. - */ -PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock, - const pj_sockaddr_t *addr, - int len) -{ - PJ_CHECK_STACK(); - - PJ_ASSERT_RETURN(addr && len > 0, PJ_EINVAL); - - if (bind(sock, (struct sockaddr*)addr, len) != 0) - return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); - else - return PJ_SUCCESS; -} - - -/* - * Bind socket. - */ -PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock, - pj_uint32_t addr32, - pj_uint16_t port) -{ - pj_sockaddr_in addr; - - PJ_CHECK_STACK(); - - addr.sin_family = PJ_AF_INET; - addr.sin_addr.s_addr = pj_htonl(addr32); - addr.sin_port = pj_htons(port); - - return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in)); -} - - -/* - * Close socket. - */ -PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock) -{ - int rc; - - PJ_CHECK_STACK(); -#if defined(PJ_WIN32) && PJ_WIN32==1 - rc = closesocket(sock); -#else - rc = close(sock); -#endif - - if (rc != 0) - return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); - else - return PJ_SUCCESS; -} - -/* - * Get remote's name. - */ -PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock, - pj_sockaddr_t *addr, - int *namelen) -{ - PJ_CHECK_STACK(); - if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0) - return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); - else - return PJ_SUCCESS; -} - -/* - * Get socket name. - */ -PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock, - pj_sockaddr_t *addr, - int *namelen) -{ - PJ_CHECK_STACK(); - if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0) - return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); - else - return PJ_SUCCESS; -} - -/* - * Send data - */ -PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock, - const void *buf, - pj_ssize_t *len, - unsigned flags) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(len, PJ_EINVAL); - - *len = send(sock, (const char*)buf, *len, flags); - - if (*len < 0) - return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); - else - return PJ_SUCCESS; -} - - -/* - * Send data. - */ -PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock, - const void *buf, - pj_ssize_t *len, - unsigned flags, - const pj_sockaddr_t *to, - int tolen) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(len, PJ_EINVAL); - - *len = sendto(sock, (const char*)buf, *len, flags, - (const struct sockaddr*)to, tolen); - - if (*len < 0) - return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); - else - return PJ_SUCCESS; -} - -/* - * Receive data. - */ -PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock, - void *buf, - pj_ssize_t *len, - unsigned flags) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(buf && len, PJ_EINVAL); - - *len = recv(sock, (char*)buf, *len, flags); - - if (*len < 0) - return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); - else - return PJ_SUCCESS; -} - -/* - * Receive data. - */ -PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock, - void *buf, - pj_ssize_t *len, - unsigned flags, - pj_sockaddr_t *from, - int *fromlen) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(buf && len, PJ_EINVAL); - PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL)); - - *len = recvfrom(sock, (char*)buf, *len, flags, - (struct sockaddr*)from, (socklen_t*)fromlen); - - if (*len < 0) - return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); - else - return PJ_SUCCESS; -} - -/* - * Get socket option. - */ -PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock, - int level, - int optname, - void *optval, - int *optlen) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(optval && optlen, PJ_EINVAL); - - if (getsockopt(sock, level, optname, (char*)optval, (socklen_t*)optlen)!=0) - return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); - else - return PJ_SUCCESS; -} - -/* - * Set socket option. - */ -PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock, - int level, - int optname, - const void *optval, - int optlen) -{ - PJ_CHECK_STACK(); - if (setsockopt(sock, level, optname, (const char*)optval, optlen) != 0) - return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); - else - return PJ_SUCCESS; -} - -/* - * Shutdown socket. - */ -#if PJ_HAS_TCP -PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock, - int how) -{ - PJ_CHECK_STACK(); - if (shutdown(sock, how) != 0) - return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); - else - return PJ_SUCCESS; -} - -/* - * Start listening to incoming connections. - */ -PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock, - int backlog) -{ - PJ_CHECK_STACK(); - if (listen(sock, backlog) != 0) - return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); - else - return PJ_SUCCESS; -} - -/* - * Connect socket. - */ -PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock, - const pj_sockaddr_t *addr, - int namelen) -{ - PJ_CHECK_STACK(); - if (connect(sock, (struct sockaddr*)addr, namelen) != 0) - return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); - else - return PJ_SUCCESS; -} - -/* - * Accept incoming connections - */ -PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd, - pj_sock_t *newsock, - pj_sockaddr_t *addr, - int *addrlen) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL); - - *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen); - if (*newsock==PJ_INVALID_SOCKET) - return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); - else - return PJ_SUCCESS; -} -#endif /* PJ_HAS_TCP */ - - +/* $Header: /pjproject-0.3/pjlib/src/pj/sock_bsd.c 10 10/29/05 11:51a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/sock_bsd.c $ + * + * 10 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 9 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 8 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 7 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include +#include +#include +#include +#include +#include + +/* + * Address families conversion. + * The values here are indexed based on pj_addr_family-0xFF00. + */ +const pj_uint16_t PJ_AF_UNIX = AF_UNIX; +const pj_uint16_t PJ_AF_INET = AF_INET; +const pj_uint16_t PJ_AF_INET6 = AF_INET6; +#ifdef AF_PACKET +const pj_uint16_t PJ_AF_PACKET = AF_PACKET; +#else +const pj_uint16_t PJ_AF_PACKET = 0xFFFF; +#endif +#ifdef AF_IRDA +const pj_uint16_t PJ_AF_IRDA = AF_IRDA; +#else +const pj_uint16_t PJ_AF_IRDA = 0xFFFF; +#endif + +/* + * Socket types conversion. + * The values here are indexed based on pj_sock_type-0xFF00 + */ +const pj_uint16_t PJ_SOCK_STREAM = SOCK_STREAM; +const pj_uint16_t PJ_SOCK_DGRAM = SOCK_DGRAM; +const pj_uint16_t PJ_SOCK_RAW = SOCK_RAW; +const pj_uint16_t PJ_SOCK_RDM = SOCK_RDM; + +/* + * Socket level values. + */ +const pj_uint16_t PJ_SOL_SOCKET = SOL_SOCKET; +#ifdef SOL_IP +const pj_uint16_t PJ_SOL_IP = SOL_IP; +#else +const pj_uint16_t PJ_SOL_IP = 0xFFFF; +#endif /* SOL_IP */ +#if defined(SOL_TCP) +const pj_uint16_t PJ_SOL_TCP = SOL_TCP; +#elif defined(IPPROTO_TCP) +const pj_uint16_t PJ_SOL_TCP = IPPROTO_TCP; +#endif /* SOL_TCP */ +#ifdef SOL_UDP +const pj_uint16_t PJ_SOL_UDP = SOL_UDP; +#else +const pj_uint16_t PJ_SOL_UDP = 0xFFFF; +#endif +#ifdef SOL_IPV6 +const pj_uint16_t PJ_SOL_IPV6 = SOL_IPV6; +#else +const pj_uint16_t PJ_SOL_IPV6 = 0xFFFF; +#endif + + +/* + * Convert 16-bit value from network byte order to host byte order. + */ +PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort) +{ + return ntohs(netshort); +} + +/* + * Convert 16-bit value from host byte order to network byte order. + */ +PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort) +{ + return htons(hostshort); +} + +/* + * Convert 32-bit value from network byte order to host byte order. + */ +PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong) +{ + return ntohl(netlong); +} + +/* + * Convert 32-bit value from host byte order to network byte order. + */ +PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong) +{ + return htonl(hostlong); +} + +/* + * Convert an Internet host address given in network byte order + * to string in standard numbers and dots notation. + */ +PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr) +{ + return inet_ntoa(*(struct in_addr*)&inaddr); +} + +/* + * This function converts the Internet host address cp from the standard + * numbers-and-dots notation into binary data and stores it in the structure + * that inp points to. + */ +PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp) +{ + char tempaddr[16]; + + /* Initialize output with PJ_INADDR_NONE. + * Some apps relies on this instead of the return value + * (and anyway the return value is quite confusing!) + */ + inp->s_addr = PJ_INADDR_NONE; + + /* Caution: + * this function might be called with cp->slen >= 16 + * (i.e. when called with hostname to check if it's an IP addr). + */ + PJ_ASSERT_RETURN(cp && cp->slen && inp, 0); + if (cp->slen >= 16) { + return 0; + } + + pj_memcpy(tempaddr, cp->ptr, cp->slen); + tempaddr[cp->slen] = '\0'; + +#if defined(PJ_SOCK_HAS_INET_ATON) && PJ_SOCK_HAS_INET_ATON != 0 + return inet_aton(tempaddr, (struct in_addr*)inp); +#else + inp->s_addr = inet_addr(tempaddr); + return inp->s_addr == PJ_INADDR_NONE ? 0 : 1; +#endif +} + +/* + * Convert address string with numbers and dots to binary IP address. + */ +PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp) +{ + pj_in_addr addr; + + pj_inet_aton(cp, &addr); + return addr; +} + +/* + * Set the IP address of an IP socket address from string address, + * with resolving the host if necessary. The string address may be in a + * standard numbers and dots notation or may be a hostname. If hostname + * is specified, then the function will resolve the host into the IP + * address. + */ +PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr, + const pj_str_t *str_addr) +{ + PJ_CHECK_STACK(); + + PJ_ASSERT_RETURN(str_addr && str_addr->slen < PJ_MAX_HOSTNAME, + (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL)); + + addr->sin_family = AF_INET; + + if (str_addr && str_addr->slen) { + addr->sin_addr = pj_inet_addr(str_addr); + if (addr->sin_addr.s_addr == PJ_INADDR_NONE) { + pj_hostent he; + pj_status_t rc; + + rc = pj_gethostbyname(str_addr, &he); + if (rc == 0) { + addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr; + } else { + addr->sin_addr.s_addr = PJ_INADDR_NONE; + return rc; + } + } + + } else { + addr->sin_addr.s_addr = 0; + } + + return PJ_SUCCESS; +} + +/* + * Set the IP address and port of an IP socket address. + * The string address may be in a standard numbers and dots notation or + * may be a hostname. If hostname is specified, then the function will + * resolve the host into the IP address. + */ +PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr, + const pj_str_t *str_addr, + pj_uint16_t port) +{ + PJ_ASSERT_RETURN(addr && str_addr, + (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL)); + + addr->sin_family = PJ_AF_INET; + pj_sockaddr_in_set_port(addr, port); + return pj_sockaddr_in_set_str_addr(addr, str_addr); +} + + +/* + * Get hostname. + */ +PJ_DEF(const pj_str_t*) pj_gethostname(void) +{ + static char buf[PJ_MAX_HOSTNAME]; + static pj_str_t hostname; + + PJ_CHECK_STACK(); + + if (hostname.ptr == NULL) { + hostname.ptr = buf; + if (gethostname(buf, sizeof(buf)) != 0) { + hostname.ptr[0] = '\0'; + hostname.slen = 0; + } else { + hostname.slen = strlen(buf); + } + } + return &hostname; +} + +/* + * Get first IP address associated with the hostname. + */ +PJ_DEF(pj_in_addr) pj_gethostaddr(void) +{ + pj_sockaddr_in addr; + const pj_str_t *hostname = pj_gethostname(); + + pj_sockaddr_in_set_str_addr(&addr, hostname); + return addr.sin_addr; +} + + +#if defined(PJ_WIN32) +/* + * Create new socket/endpoint for communication and returns a descriptor. + */ +PJ_DEF(pj_status_t) pj_sock_socket(int af, + int type, + int proto, + pj_sock_t *sock) +{ + PJ_CHECK_STACK(); + + /* Sanity checks. */ + PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL); + PJ_ASSERT_RETURN((unsigned)PJ_INVALID_SOCKET==INVALID_SOCKET, + (*sock=PJ_INVALID_SOCKET, PJ_EINVAL)); + + *sock = WSASocket(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED); + + if (*sock == PJ_INVALID_SOCKET) + return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); + else + return PJ_SUCCESS; +} + +#else +/* + * Create new socket/endpoint for communication and returns a descriptor. + */ +PJ_DEF(pj_status_t) pj_sock_socket(int af, + int type, + int proto, + pj_sock_t *sock) +{ + + PJ_CHECK_STACK(); + + /* Sanity checks. */ + PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL); + PJ_ASSERT_RETURN(PJ_INVALID_SOCKET==-1, + (*sock=PJ_INVALID_SOCKET, PJ_EINVAL)); + + *sock = socket(af, type, proto); + if (*sock == PJ_INVALID_SOCKET) + return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); + else + return PJ_SUCCESS; +} +#endif + + +/* + * Bind socket. + */ +PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock, + const pj_sockaddr_t *addr, + int len) +{ + PJ_CHECK_STACK(); + + PJ_ASSERT_RETURN(addr && len > 0, PJ_EINVAL); + + if (bind(sock, (struct sockaddr*)addr, len) != 0) + return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); + else + return PJ_SUCCESS; +} + + +/* + * Bind socket. + */ +PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock, + pj_uint32_t addr32, + pj_uint16_t port) +{ + pj_sockaddr_in addr; + + PJ_CHECK_STACK(); + + addr.sin_family = PJ_AF_INET; + addr.sin_addr.s_addr = pj_htonl(addr32); + addr.sin_port = pj_htons(port); + + return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in)); +} + + +/* + * Close socket. + */ +PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock) +{ + int rc; + + PJ_CHECK_STACK(); +#if defined(PJ_WIN32) && PJ_WIN32==1 + rc = closesocket(sock); +#else + rc = close(sock); +#endif + + if (rc != 0) + return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); + else + return PJ_SUCCESS; +} + +/* + * Get remote's name. + */ +PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock, + pj_sockaddr_t *addr, + int *namelen) +{ + PJ_CHECK_STACK(); + if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0) + return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); + else + return PJ_SUCCESS; +} + +/* + * Get socket name. + */ +PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock, + pj_sockaddr_t *addr, + int *namelen) +{ + PJ_CHECK_STACK(); + if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0) + return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); + else + return PJ_SUCCESS; +} + +/* + * Send data + */ +PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock, + const void *buf, + pj_ssize_t *len, + unsigned flags) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(len, PJ_EINVAL); + + *len = send(sock, (const char*)buf, *len, flags); + + if (*len < 0) + return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); + else + return PJ_SUCCESS; +} + + +/* + * Send data. + */ +PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock, + const void *buf, + pj_ssize_t *len, + unsigned flags, + const pj_sockaddr_t *to, + int tolen) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(len, PJ_EINVAL); + + *len = sendto(sock, (const char*)buf, *len, flags, + (const struct sockaddr*)to, tolen); + + if (*len < 0) + return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); + else + return PJ_SUCCESS; +} + +/* + * Receive data. + */ +PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock, + void *buf, + pj_ssize_t *len, + unsigned flags) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(buf && len, PJ_EINVAL); + + *len = recv(sock, (char*)buf, *len, flags); + + if (*len < 0) + return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); + else + return PJ_SUCCESS; +} + +/* + * Receive data. + */ +PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock, + void *buf, + pj_ssize_t *len, + unsigned flags, + pj_sockaddr_t *from, + int *fromlen) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(buf && len, PJ_EINVAL); + PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL)); + + *len = recvfrom(sock, (char*)buf, *len, flags, + (struct sockaddr*)from, (socklen_t*)fromlen); + + if (*len < 0) + return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); + else + return PJ_SUCCESS; +} + +/* + * Get socket option. + */ +PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock, + int level, + int optname, + void *optval, + int *optlen) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(optval && optlen, PJ_EINVAL); + + if (getsockopt(sock, level, optname, (char*)optval, (socklen_t*)optlen)!=0) + return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); + else + return PJ_SUCCESS; +} + +/* + * Set socket option. + */ +PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock, + int level, + int optname, + const void *optval, + int optlen) +{ + PJ_CHECK_STACK(); + if (setsockopt(sock, level, optname, (const char*)optval, optlen) != 0) + return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); + else + return PJ_SUCCESS; +} + +/* + * Shutdown socket. + */ +#if PJ_HAS_TCP +PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock, + int how) +{ + PJ_CHECK_STACK(); + if (shutdown(sock, how) != 0) + return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); + else + return PJ_SUCCESS; +} + +/* + * Start listening to incoming connections. + */ +PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock, + int backlog) +{ + PJ_CHECK_STACK(); + if (listen(sock, backlog) != 0) + return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); + else + return PJ_SUCCESS; +} + +/* + * Connect socket. + */ +PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock, + const pj_sockaddr_t *addr, + int namelen) +{ + PJ_CHECK_STACK(); + if (connect(sock, (struct sockaddr*)addr, namelen) != 0) + return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); + else + return PJ_SUCCESS; +} + +/* + * Accept incoming connections + */ +PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd, + pj_sock_t *newsock, + pj_sockaddr_t *addr, + int *addrlen) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL); + + *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen); + if (*newsock==PJ_INVALID_SOCKET) + return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); + else + return PJ_SUCCESS; +} +#endif /* PJ_HAS_TCP */ + + diff --git a/pjlib/src/pj/sock_linux_kernel.c b/pjlib/src/pj/sock_linux_kernel.c index 76bc7bd8..28ed07af 100644 --- a/pjlib/src/pj/sock_linux_kernel.c +++ b/pjlib/src/pj/sock_linux_kernel.c @@ -1,749 +1,749 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/sock_linux_kernel.c 4 10/29/05 11:51a Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pj/sock_linux_kernel.c $ - * - * 4 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 3 10/20/05 9:19a Bennylp - * Updated with new API convention (error code) - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 10/05/05 4:43p Bennylp - * Created. - * - */ -#include -#include -#include /* pj_memcpy() */ -#include /* PJ_CHECK_STACK() */ -#include /* pj_gethostbyname() */ -#include -#include -#include -#include - -/* Linux kernel specific. */ -#include -#include -//#include -#include -#include /* sys_xxx() */ -#include /* FIONBIO */ -#include /* for pj_gethostname() */ - -/* - * Address families conversion. - * The values here are indexed based on pj_addr_family-0xFF00. - */ -const pj_uint16_t PJ_AF_UNIX = AF_UNIX; -const pj_uint16_t PJ_AF_INET = AF_INET; -const pj_uint16_t PJ_AF_INET6 = AF_INET6; -#ifdef AF_PACKET -const pj_uint16_t PJ_AF_PACKET = AF_PACKET; -#else -# error "AF_PACKET undeclared!" -#endif -#ifdef AF_IRDA -const pj_uint16_t PJ_AF_IRDA = AF_IRDA; -#else -# error "AF_IRDA undeclared!" -#endif - -/* - * Socket types conversion. - * The values here are indexed based on pj_sock_type-0xFF00 - */ -const pj_uint16_t PJ_SOCK_STREAM= SOCK_STREAM; -const pj_uint16_t PJ_SOCK_DGRAM = SOCK_DGRAM; -const pj_uint16_t PJ_SOCK_RAW = SOCK_RAW; -const pj_uint16_t PJ_SOCK_RDM = SOCK_RDM; - -/* - * Socket level values. - */ -const pj_uint16_t PJ_SOL_SOCKET = SOL_SOCKET; -#ifdef SOL_IP -const pj_uint16_t PJ_SOL_IP = SOL_IP; -#else -# error "SOL_IP undeclared!" -#endif /* SOL_IP */ -#if defined(SOL_TCP) -const pj_uint16_t PJ_SOL_TCP = SOL_TCP; -#else -# error "SOL_TCP undeclared!" -#endif /* SOL_TCP */ -#ifdef SOL_UDP -const pj_uint16_t PJ_SOL_UDP = SOL_UDP; -#else -# error "SOL_UDP undeclared!" -#endif -#ifdef SOL_IPV6 -const pj_uint16_t PJ_SOL_IPV6 = SOL_IPV6; -#else -# error "SOL_IPV6 undeclared!" -#endif - -/* - * Convert 16-bit value from network byte order to host byte order. - */ -PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort) -{ - return ntohs(netshort); -} - -/* - * Convert 16-bit value from host byte order to network byte order. - */ -PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort) -{ - return htons(hostshort); -} - -/* - * Convert 32-bit value from network byte order to host byte order. - */ -PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong) -{ - return ntohl(netlong); -} - -/* - * Convert 32-bit value from host byte order to network byte order. - */ -PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong) -{ - return htonl(hostlong); -} - -/* - * Convert an Internet host address given in network byte order - * to string in standard numbers and dots notation. - */ -PJ_DEF(char*) pj_inet_ntoa(pj_in_addr in) -{ -#define UC(b) (((int)b)&0xff) - static char b[18]; - char *p; - - p = (char *)∈ - pj_snprintf(b, sizeof(b), "%d.%d.%d.%d", - UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3])); - - return b; -} - -/* - * This function converts the Internet host address ccp from the standard - * numbers-and-dots notation into binary data and stores it in the structure - * that inp points to. - */ -PJ_DEF(int) pj_inet_aton(const pj_str_t *ccp, struct pj_in_addr *addr) -{ - pj_uint32_t val; - int base, n; - char c; - unsigned parts[4]; - unsigned *pp = parts; - char cp_copy[18]; - char *cp = cp_copy; - - addr->s_addr = PJ_INADDR_NONE; - - if (ccp->slen > 15) return 0; - - pj_memcpy(cp, ccp->ptr, ccp->slen); - cp[ccp->slen] = '\0'; - - c = *cp; - for (;;) { - /* - * Collect number up to ``.''. - * Values are specified as for C: - * 0x=hex, 0=octal, isdigit=decimal. - */ - if (!pj_isdigit((int)c)) - return (0); - val = 0; base = 10; - if (c == '0') { - c = *++cp; - if (c == 'x' || c == 'X') - base = 16, c = *++cp; - else - base = 8; - } - - for (;;) { - if (pj_isascii((int)c) && pj_isdigit((int)c)) { - val = (val * base) + (c - '0'); - c = *++cp; - } else if (base==16 && pj_isascii((int)c) && pj_isxdigit((int)c)) { - val = (val << 4) | - (c + 10 - (pj_islower((int)c) ? 'a' : 'A')); - c = *++cp; - } else - break; - } - - if (c == '.') { - /* - * Internet format: - * a.b.c.d - * a.b.c (with c treated as 16 bits) - * a.b (with b treated as 24 bits) - */ - if (pp >= parts + 3) - return (0); - *pp++ = val; - c = *++cp; - } else - break; - } - - /* - * Check for trailing characters. - */ - if (c != '\0' && (!pj_isascii((int)c) || !pj_isspace((int)c))) - return (0); - /* - * Concoct the address according to - * the number of parts specified. - */ - n = pp - parts + 1; - switch (n) { - case 0: - return (0); /* initial nondigit */ - case 1: /* a -- 32 bits */ - break; - case 2: /* a.b -- 8.24 bits */ - if (val > 0xffffff) - return (0); - val |= parts[0] << 24; - break; - case 3: /* a.b.c -- 8.8.16 bits */ - if (val > 0xffff) - return (0); - val |= (parts[0] << 24) | (parts[1] << 16); - break; - case 4: /* a.b.c.d -- 8.8.8.8 bits */ - if (val > 0xff) - return (0); - val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); - break; - } - - if (addr) - addr->s_addr = pj_htonl(val); - return (1); -} - -/* - * Convert address string with numbers and dots to binary IP address. - */ -PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp) -{ - pj_in_addr addr; - pj_inet_aton(cp, &addr); - return addr; -} - -/* - * Set the IP address of an IP socket address from string address, - * with resolving the host if necessary. The string address may be in a - * standard numbers and dots notation or may be a hostname. If hostname - * is specified, then the function will resolve the host into the IP - * address. - */ -PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr, - const pj_str_t *str_addr) -{ - PJ_CHECK_STACK(); - - pj_assert(str_addr && str_addr->slen < PJ_MAX_HOSTNAME); - - addr->sin_family = AF_INET; - - if (str_addr && str_addr->slen) { - addr->sin_addr = pj_inet_addr(str_addr); - if (addr->sin_addr.s_addr == PJ_INADDR_NONE) { - pj_hostent he; - if (pj_gethostbyname(str_addr, &he) == 0) { - addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr; - } else { - addr->sin_addr.s_addr = PJ_INADDR_NONE; - return -1; - } - } - - } else { - addr->sin_addr.s_addr = 0; - } - - return PJ_SUCCESS; -} - -/* - * Set the IP address and port of an IP socket address. - * The string address may be in a standard numbers and dots notation or - * may be a hostname. If hostname is specified, then the function will - * resolve the host into the IP address. - */ -PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr, - const pj_str_t *str_addr, - pj_uint16_t port) -{ - pj_assert(addr && str_addr); - - addr->sin_family = PJ_AF_INET; - pj_sockaddr_in_set_port(addr, port); - return pj_sockaddr_in_set_str_addr(addr, str_addr); -} - - -/* - * Get hostname. - */ -PJ_DEF(const pj_str_t*) pj_gethostname(void) -{ - static char buf[PJ_MAX_HOSTNAME]; - static pj_str_t hostname; - - PJ_CHECK_STACK(); - - if (hostname.ptr == NULL) { - hostname.ptr = buf; - down_read(&uts_sem); - hostname.slen = strlen(system_utsname.nodename); - if (hostname.slen > PJ_MAX_HOSTNAME) { - hostname.ptr[0] = '\0'; - hostname.slen = 0; - } else { - pj_memcpy(hostname.ptr, system_utsname.nodename, hostname.slen); - } - up_read(&uts_sem); - } - return &hostname; -} - -/* - * Get first IP address associated with the hostname. - */ -PJ_DEF(pj_in_addr) pj_gethostaddr(void) -{ - pj_sockaddr_in addr; - const pj_str_t *hostname = pj_gethostname(); - - pj_sockaddr_in_set_str_addr(&addr, hostname); - return addr.sin_addr; -} - - -/* - * Create new socket/endpoint for communication and returns a descriptor. - */ -PJ_DEF(pj_status_t) pj_sock_socket(int af, int type, int proto, - pj_sock_t *sock_fd) -{ - long result; - - PJ_CHECK_STACK(); - - /* Sanity checks. */ - PJ_ASSERT_RETURN(PJ_INVALID_SOCKET == -1 && sock_fd != NULL, PJ_EINVAL); - - /* Initialize returned socket */ - *sock_fd = PJ_INVALID_SOCKET; - - /* Create socket. */ - result = sys_socket(af, type, proto); - if (result < 0) { - return PJ_RETURN_OS_ERROR((-result)); - } - - *sock_fd = result; - - return PJ_SUCCESS; -} - -/* - * Bind socket. - */ -PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sockfd, - const pj_sockaddr_t *addr, - int len) -{ - long err; - mm_segment_t oldfs; - - PJ_CHECK_STACK(); - - PJ_ASSERT_RETURN(addr!=NULL && len >= sizeof(struct pj_sockaddr), - PJ_EINVAL); - - oldfs = get_fs(); - set_fs(KERNEL_DS); - - err = sys_bind(sockfd, (struct sockaddr*)addr, len); - - set_fs(oldfs); - - if (err) - return PJ_RETURN_OS_ERROR(-err); - else - return PJ_SUCCESS; -} - - -/* - * Bind socket. - */ -PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sockfd, - pj_uint32_t addr32, - pj_uint16_t port) -{ - pj_sockaddr_in addr; - - PJ_CHECK_STACK(); - - addr.sin_family = PJ_AF_INET; - addr.sin_addr.s_addr = pj_htonl(addr32); - addr.sin_port = pj_htons(port); - - return pj_sock_bind(sockfd, &addr, sizeof(pj_sockaddr_in)); -} - -/* - * Close socket. - */ -PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sockfd) -{ - long err; - - err = sys_close(sockfd); - - if (err != 0) - return PJ_RETURN_OS_ERROR(-err); - else - return PJ_SUCCESS; -} - -/* - * Get remote's name. - */ -PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sockfd, - pj_sockaddr_t *addr, - int *namelen) -{ - mm_segment_t oldfs; - long err; - - PJ_CHECK_STACK(); - - oldfs = get_fs(); - set_fs(KERNEL_DS); - - err = sys_getpeername( sockfd, addr, namelen); - - set_fs(oldfs); - - if (err) - return PJ_RETURN_OS_ERROR(-err); - else - return PJ_SUCCESS; -} - -/* - * Get socket name. - */ -PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sockfd, - pj_sockaddr_t *addr, - int *namelen) -{ - mm_segment_t oldfs; - int err; - - PJ_CHECK_STACK(); - - oldfs = get_fs(); - set_fs(KERNEL_DS); - - err = sys_getsockname( sockfd, addr, namelen ); - - set_fs(oldfs); - - if (err) - return PJ_RETURN_OS_ERROR(-err); - else - return PJ_SUCCESS; -} - -/* - * Send data - */ -PJ_DEF(pj_status_t) pj_sock_send( pj_sock_t sockfd, - const void *buf, - pj_ssize_t *len, - unsigned flags) -{ - return pj_sock_sendto(sockfd, buf, len, flags, NULL, 0); -} - - -/* - * Send data. - */ -PJ_DEF(pj_status_t) pj_sock_sendto( pj_sock_t sockfd, - const void *buff, - pj_ssize_t *len, - unsigned flags, - const pj_sockaddr_t *addr, - int addr_len) -{ - long err; - mm_segment_t oldfs; - - PJ_CHECK_STACK(); - - oldfs = get_fs(); - set_fs(KERNEL_DS); - - err = *len = sys_sendto( sockfd, (void*)buff, *len, flags, - (void*)addr, addr_len ); - - set_fs(oldfs); - - if (err >= 0) { - return PJ_SUCCESS; - } - else { - return PJ_RETURN_OS_ERROR(-err); - } -} - -/* - * Receive data. - */ -PJ_DEF(pj_status_t) pj_sock_recv( pj_sock_t sockfd, - void *buf, - pj_ssize_t *len, - unsigned flags) -{ - return pj_sock_recvfrom(sockfd, buf, len, flags, NULL, NULL); -} - -/* - * Receive data. - */ -PJ_DEF(pj_status_t) pj_sock_recvfrom( pj_sock_t sockfd, - void *buff, - pj_ssize_t *size, - unsigned flags, - pj_sockaddr_t *from, - int *fromlen) -{ - mm_segment_t oldfs; - long err; - - PJ_CHECK_STACK(); - - oldfs = get_fs(); - set_fs(KERNEL_DS); - - err = *size = sys_recvfrom( sockfd, buff, *size, flags, from, fromlen); - - set_fs(oldfs); - - if (err >= 0) { - return PJ_SUCCESS; - } - else { - return PJ_RETURN_OS_ERROR(-err); - } -} - -/* - * Get socket option. - */ -PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sockfd, - int level, - int optname, - void *optval, - int *optlen) -{ - mm_segment_t oldfs; - long err; - - PJ_CHECK_STACK(); - - oldfs = get_fs(); - set_fs(KERNEL_DS); - - err = sys_getsockopt( sockfd, level, optname, optval, optlen); - - set_fs(oldfs); - - if (err) - return PJ_RETURN_OS_ERROR(-err); - else - return PJ_SUCCESS; -} - -/* - * Set socket option. - */ -PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sockfd, - int level, - int optname, - const void *optval, - int optlen) -{ - long err; - mm_segment_t oldfs; - - PJ_CHECK_STACK(); - - - oldfs = get_fs(); - set_fs(KERNEL_DS); - - err = sys_setsockopt( sockfd, level, optname, (void*)optval, optlen); - - set_fs(oldfs); - - if (err) - return PJ_RETURN_OS_ERROR(-err); - else - return PJ_SUCCESS; -} - -/* - * Shutdown socket. - */ -#if PJ_HAS_TCP -PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sockfd, - int how) -{ - long err; - - PJ_CHECK_STACK(); - - err = sys_shutdown(sockfd, how); - - if (err) - return PJ_RETURN_OS_ERROR(-err); - else - return PJ_SUCCESS; -} - -/* - * Start listening to incoming connections. - */ -PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sockfd, - int backlog) -{ - long err; - - PJ_CHECK_STACK(); - - err = sys_listen( sockfd, backlog ); - - if (err) - return PJ_RETURN_OS_ERROR(-err); - else - return PJ_SUCCESS; -} - -/* - * Connect socket. - */ -PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sockfd, - const pj_sockaddr_t *addr, - int namelen) -{ - long err; - mm_segment_t oldfs; - - PJ_CHECK_STACK(); - - oldfs = get_fs(); - set_fs(KERNEL_DS); - - err = sys_connect( sockfd, (void*)addr, namelen ); - - set_fs(oldfs); - - if (err) - return PJ_RETURN_OS_ERROR(-err); - else - return PJ_SUCCESS; -} - -/* - * Accept incoming connections - */ -PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t sockfd, - pj_sock_t *newsockfd, - pj_sockaddr_t *addr, - int *addrlen) -{ - long err; - - PJ_CHECK_STACK(); - - PJ_ASSERT_RETURN(newsockfd != NULL, PJ_EINVAL); - - err = sys_accept( sockfd, addr, addrlen); - - if (err < 0) { - *newsockfd = PJ_INVALID_SOCKET; - return PJ_RETURN_OS_ERROR(-err); - } - else { - *newsockfd = err; - return PJ_SUCCESS; - } -} -#endif /* PJ_HAS_TCP */ - - - -/* - * Permission to steal inet_ntoa() and inet_aton() as long as this notice below - * is included: - */ -/* - * Copyright (c) 1983, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - +/* $Header: /pjproject-0.3/pjlib/src/pj/sock_linux_kernel.c 4 10/29/05 11:51a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pj/sock_linux_kernel.c $ + * + * 4 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 3 10/20/05 9:19a Bennylp + * Updated with new API convention (error code) + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 10/05/05 4:43p Bennylp + * Created. + * + */ +#include +#include +#include /* pj_memcpy() */ +#include /* PJ_CHECK_STACK() */ +#include /* pj_gethostbyname() */ +#include +#include +#include +#include + +/* Linux kernel specific. */ +#include +#include +//#include +#include +#include /* sys_xxx() */ +#include /* FIONBIO */ +#include /* for pj_gethostname() */ + +/* + * Address families conversion. + * The values here are indexed based on pj_addr_family-0xFF00. + */ +const pj_uint16_t PJ_AF_UNIX = AF_UNIX; +const pj_uint16_t PJ_AF_INET = AF_INET; +const pj_uint16_t PJ_AF_INET6 = AF_INET6; +#ifdef AF_PACKET +const pj_uint16_t PJ_AF_PACKET = AF_PACKET; +#else +# error "AF_PACKET undeclared!" +#endif +#ifdef AF_IRDA +const pj_uint16_t PJ_AF_IRDA = AF_IRDA; +#else +# error "AF_IRDA undeclared!" +#endif + +/* + * Socket types conversion. + * The values here are indexed based on pj_sock_type-0xFF00 + */ +const pj_uint16_t PJ_SOCK_STREAM= SOCK_STREAM; +const pj_uint16_t PJ_SOCK_DGRAM = SOCK_DGRAM; +const pj_uint16_t PJ_SOCK_RAW = SOCK_RAW; +const pj_uint16_t PJ_SOCK_RDM = SOCK_RDM; + +/* + * Socket level values. + */ +const pj_uint16_t PJ_SOL_SOCKET = SOL_SOCKET; +#ifdef SOL_IP +const pj_uint16_t PJ_SOL_IP = SOL_IP; +#else +# error "SOL_IP undeclared!" +#endif /* SOL_IP */ +#if defined(SOL_TCP) +const pj_uint16_t PJ_SOL_TCP = SOL_TCP; +#else +# error "SOL_TCP undeclared!" +#endif /* SOL_TCP */ +#ifdef SOL_UDP +const pj_uint16_t PJ_SOL_UDP = SOL_UDP; +#else +# error "SOL_UDP undeclared!" +#endif +#ifdef SOL_IPV6 +const pj_uint16_t PJ_SOL_IPV6 = SOL_IPV6; +#else +# error "SOL_IPV6 undeclared!" +#endif + +/* + * Convert 16-bit value from network byte order to host byte order. + */ +PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort) +{ + return ntohs(netshort); +} + +/* + * Convert 16-bit value from host byte order to network byte order. + */ +PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort) +{ + return htons(hostshort); +} + +/* + * Convert 32-bit value from network byte order to host byte order. + */ +PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong) +{ + return ntohl(netlong); +} + +/* + * Convert 32-bit value from host byte order to network byte order. + */ +PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong) +{ + return htonl(hostlong); +} + +/* + * Convert an Internet host address given in network byte order + * to string in standard numbers and dots notation. + */ +PJ_DEF(char*) pj_inet_ntoa(pj_in_addr in) +{ +#define UC(b) (((int)b)&0xff) + static char b[18]; + char *p; + + p = (char *)∈ + pj_snprintf(b, sizeof(b), "%d.%d.%d.%d", + UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3])); + + return b; +} + +/* + * This function converts the Internet host address ccp from the standard + * numbers-and-dots notation into binary data and stores it in the structure + * that inp points to. + */ +PJ_DEF(int) pj_inet_aton(const pj_str_t *ccp, struct pj_in_addr *addr) +{ + pj_uint32_t val; + int base, n; + char c; + unsigned parts[4]; + unsigned *pp = parts; + char cp_copy[18]; + char *cp = cp_copy; + + addr->s_addr = PJ_INADDR_NONE; + + if (ccp->slen > 15) return 0; + + pj_memcpy(cp, ccp->ptr, ccp->slen); + cp[ccp->slen] = '\0'; + + c = *cp; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, isdigit=decimal. + */ + if (!pj_isdigit((int)c)) + return (0); + val = 0; base = 10; + if (c == '0') { + c = *++cp; + if (c == 'x' || c == 'X') + base = 16, c = *++cp; + else + base = 8; + } + + for (;;) { + if (pj_isascii((int)c) && pj_isdigit((int)c)) { + val = (val * base) + (c - '0'); + c = *++cp; + } else if (base==16 && pj_isascii((int)c) && pj_isxdigit((int)c)) { + val = (val << 4) | + (c + 10 - (pj_islower((int)c) ? 'a' : 'A')); + c = *++cp; + } else + break; + } + + if (c == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3) + return (0); + *pp++ = val; + c = *++cp; + } else + break; + } + + /* + * Check for trailing characters. + */ + if (c != '\0' && (!pj_isascii((int)c) || !pj_isspace((int)c))) + return (0); + /* + * Concoct the address according to + * the number of parts specified. + */ + n = pp - parts + 1; + switch (n) { + case 0: + return (0); /* initial nondigit */ + case 1: /* a -- 32 bits */ + break; + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffff) + return (0); + val |= parts[0] << 24; + break; + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16); + break; + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + + if (addr) + addr->s_addr = pj_htonl(val); + return (1); +} + +/* + * Convert address string with numbers and dots to binary IP address. + */ +PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp) +{ + pj_in_addr addr; + pj_inet_aton(cp, &addr); + return addr; +} + +/* + * Set the IP address of an IP socket address from string address, + * with resolving the host if necessary. The string address may be in a + * standard numbers and dots notation or may be a hostname. If hostname + * is specified, then the function will resolve the host into the IP + * address. + */ +PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr, + const pj_str_t *str_addr) +{ + PJ_CHECK_STACK(); + + pj_assert(str_addr && str_addr->slen < PJ_MAX_HOSTNAME); + + addr->sin_family = AF_INET; + + if (str_addr && str_addr->slen) { + addr->sin_addr = pj_inet_addr(str_addr); + if (addr->sin_addr.s_addr == PJ_INADDR_NONE) { + pj_hostent he; + if (pj_gethostbyname(str_addr, &he) == 0) { + addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr; + } else { + addr->sin_addr.s_addr = PJ_INADDR_NONE; + return -1; + } + } + + } else { + addr->sin_addr.s_addr = 0; + } + + return PJ_SUCCESS; +} + +/* + * Set the IP address and port of an IP socket address. + * The string address may be in a standard numbers and dots notation or + * may be a hostname. If hostname is specified, then the function will + * resolve the host into the IP address. + */ +PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr, + const pj_str_t *str_addr, + pj_uint16_t port) +{ + pj_assert(addr && str_addr); + + addr->sin_family = PJ_AF_INET; + pj_sockaddr_in_set_port(addr, port); + return pj_sockaddr_in_set_str_addr(addr, str_addr); +} + + +/* + * Get hostname. + */ +PJ_DEF(const pj_str_t*) pj_gethostname(void) +{ + static char buf[PJ_MAX_HOSTNAME]; + static pj_str_t hostname; + + PJ_CHECK_STACK(); + + if (hostname.ptr == NULL) { + hostname.ptr = buf; + down_read(&uts_sem); + hostname.slen = strlen(system_utsname.nodename); + if (hostname.slen > PJ_MAX_HOSTNAME) { + hostname.ptr[0] = '\0'; + hostname.slen = 0; + } else { + pj_memcpy(hostname.ptr, system_utsname.nodename, hostname.slen); + } + up_read(&uts_sem); + } + return &hostname; +} + +/* + * Get first IP address associated with the hostname. + */ +PJ_DEF(pj_in_addr) pj_gethostaddr(void) +{ + pj_sockaddr_in addr; + const pj_str_t *hostname = pj_gethostname(); + + pj_sockaddr_in_set_str_addr(&addr, hostname); + return addr.sin_addr; +} + + +/* + * Create new socket/endpoint for communication and returns a descriptor. + */ +PJ_DEF(pj_status_t) pj_sock_socket(int af, int type, int proto, + pj_sock_t *sock_fd) +{ + long result; + + PJ_CHECK_STACK(); + + /* Sanity checks. */ + PJ_ASSERT_RETURN(PJ_INVALID_SOCKET == -1 && sock_fd != NULL, PJ_EINVAL); + + /* Initialize returned socket */ + *sock_fd = PJ_INVALID_SOCKET; + + /* Create socket. */ + result = sys_socket(af, type, proto); + if (result < 0) { + return PJ_RETURN_OS_ERROR((-result)); + } + + *sock_fd = result; + + return PJ_SUCCESS; +} + +/* + * Bind socket. + */ +PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sockfd, + const pj_sockaddr_t *addr, + int len) +{ + long err; + mm_segment_t oldfs; + + PJ_CHECK_STACK(); + + PJ_ASSERT_RETURN(addr!=NULL && len >= sizeof(struct pj_sockaddr), + PJ_EINVAL); + + oldfs = get_fs(); + set_fs(KERNEL_DS); + + err = sys_bind(sockfd, (struct sockaddr*)addr, len); + + set_fs(oldfs); + + if (err) + return PJ_RETURN_OS_ERROR(-err); + else + return PJ_SUCCESS; +} + + +/* + * Bind socket. + */ +PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sockfd, + pj_uint32_t addr32, + pj_uint16_t port) +{ + pj_sockaddr_in addr; + + PJ_CHECK_STACK(); + + addr.sin_family = PJ_AF_INET; + addr.sin_addr.s_addr = pj_htonl(addr32); + addr.sin_port = pj_htons(port); + + return pj_sock_bind(sockfd, &addr, sizeof(pj_sockaddr_in)); +} + +/* + * Close socket. + */ +PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sockfd) +{ + long err; + + err = sys_close(sockfd); + + if (err != 0) + return PJ_RETURN_OS_ERROR(-err); + else + return PJ_SUCCESS; +} + +/* + * Get remote's name. + */ +PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sockfd, + pj_sockaddr_t *addr, + int *namelen) +{ + mm_segment_t oldfs; + long err; + + PJ_CHECK_STACK(); + + oldfs = get_fs(); + set_fs(KERNEL_DS); + + err = sys_getpeername( sockfd, addr, namelen); + + set_fs(oldfs); + + if (err) + return PJ_RETURN_OS_ERROR(-err); + else + return PJ_SUCCESS; +} + +/* + * Get socket name. + */ +PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sockfd, + pj_sockaddr_t *addr, + int *namelen) +{ + mm_segment_t oldfs; + int err; + + PJ_CHECK_STACK(); + + oldfs = get_fs(); + set_fs(KERNEL_DS); + + err = sys_getsockname( sockfd, addr, namelen ); + + set_fs(oldfs); + + if (err) + return PJ_RETURN_OS_ERROR(-err); + else + return PJ_SUCCESS; +} + +/* + * Send data + */ +PJ_DEF(pj_status_t) pj_sock_send( pj_sock_t sockfd, + const void *buf, + pj_ssize_t *len, + unsigned flags) +{ + return pj_sock_sendto(sockfd, buf, len, flags, NULL, 0); +} + + +/* + * Send data. + */ +PJ_DEF(pj_status_t) pj_sock_sendto( pj_sock_t sockfd, + const void *buff, + pj_ssize_t *len, + unsigned flags, + const pj_sockaddr_t *addr, + int addr_len) +{ + long err; + mm_segment_t oldfs; + + PJ_CHECK_STACK(); + + oldfs = get_fs(); + set_fs(KERNEL_DS); + + err = *len = sys_sendto( sockfd, (void*)buff, *len, flags, + (void*)addr, addr_len ); + + set_fs(oldfs); + + if (err >= 0) { + return PJ_SUCCESS; + } + else { + return PJ_RETURN_OS_ERROR(-err); + } +} + +/* + * Receive data. + */ +PJ_DEF(pj_status_t) pj_sock_recv( pj_sock_t sockfd, + void *buf, + pj_ssize_t *len, + unsigned flags) +{ + return pj_sock_recvfrom(sockfd, buf, len, flags, NULL, NULL); +} + +/* + * Receive data. + */ +PJ_DEF(pj_status_t) pj_sock_recvfrom( pj_sock_t sockfd, + void *buff, + pj_ssize_t *size, + unsigned flags, + pj_sockaddr_t *from, + int *fromlen) +{ + mm_segment_t oldfs; + long err; + + PJ_CHECK_STACK(); + + oldfs = get_fs(); + set_fs(KERNEL_DS); + + err = *size = sys_recvfrom( sockfd, buff, *size, flags, from, fromlen); + + set_fs(oldfs); + + if (err >= 0) { + return PJ_SUCCESS; + } + else { + return PJ_RETURN_OS_ERROR(-err); + } +} + +/* + * Get socket option. + */ +PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sockfd, + int level, + int optname, + void *optval, + int *optlen) +{ + mm_segment_t oldfs; + long err; + + PJ_CHECK_STACK(); + + oldfs = get_fs(); + set_fs(KERNEL_DS); + + err = sys_getsockopt( sockfd, level, optname, optval, optlen); + + set_fs(oldfs); + + if (err) + return PJ_RETURN_OS_ERROR(-err); + else + return PJ_SUCCESS; +} + +/* + * Set socket option. + */ +PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sockfd, + int level, + int optname, + const void *optval, + int optlen) +{ + long err; + mm_segment_t oldfs; + + PJ_CHECK_STACK(); + + + oldfs = get_fs(); + set_fs(KERNEL_DS); + + err = sys_setsockopt( sockfd, level, optname, (void*)optval, optlen); + + set_fs(oldfs); + + if (err) + return PJ_RETURN_OS_ERROR(-err); + else + return PJ_SUCCESS; +} + +/* + * Shutdown socket. + */ +#if PJ_HAS_TCP +PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sockfd, + int how) +{ + long err; + + PJ_CHECK_STACK(); + + err = sys_shutdown(sockfd, how); + + if (err) + return PJ_RETURN_OS_ERROR(-err); + else + return PJ_SUCCESS; +} + +/* + * Start listening to incoming connections. + */ +PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sockfd, + int backlog) +{ + long err; + + PJ_CHECK_STACK(); + + err = sys_listen( sockfd, backlog ); + + if (err) + return PJ_RETURN_OS_ERROR(-err); + else + return PJ_SUCCESS; +} + +/* + * Connect socket. + */ +PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sockfd, + const pj_sockaddr_t *addr, + int namelen) +{ + long err; + mm_segment_t oldfs; + + PJ_CHECK_STACK(); + + oldfs = get_fs(); + set_fs(KERNEL_DS); + + err = sys_connect( sockfd, (void*)addr, namelen ); + + set_fs(oldfs); + + if (err) + return PJ_RETURN_OS_ERROR(-err); + else + return PJ_SUCCESS; +} + +/* + * Accept incoming connections + */ +PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t sockfd, + pj_sock_t *newsockfd, + pj_sockaddr_t *addr, + int *addrlen) +{ + long err; + + PJ_CHECK_STACK(); + + PJ_ASSERT_RETURN(newsockfd != NULL, PJ_EINVAL); + + err = sys_accept( sockfd, addr, addrlen); + + if (err < 0) { + *newsockfd = PJ_INVALID_SOCKET; + return PJ_RETURN_OS_ERROR(-err); + } + else { + *newsockfd = err; + return PJ_SUCCESS; + } +} +#endif /* PJ_HAS_TCP */ + + + +/* + * Permission to steal inet_ntoa() and inet_aton() as long as this notice below + * is included: + */ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + diff --git a/pjlib/src/pj/sock_select.c b/pjlib/src/pj/sock_select.c index 49fa0116..146bbf37 100644 --- a/pjlib/src/pj/sock_select.c +++ b/pjlib/src/pj/sock_select.c @@ -1,101 +1,105 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/sock_select.c 4 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/sock_select.c $ - * - * 4 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 3 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - * 1 9/15/05 8:40p Bennylp - * Created. - */ -#include -#include -#include -#include -#include - - -#ifdef _MSC_VER -# pragma warning(disable: 4018) // Signed/unsigned mismatch in FD_* -#endif - -#define PART_FDSET(p_fdsetp) ((fd_set*)&p_fdsetp->data[1]) -#define PART_COUNT(p_fdsetp) (p_fdsetp->data[0]) - -PJ_DEF(void) PJ_FD_ZERO(pj_fd_set_t *fdsetp) -{ - PJ_CHECK_STACK(); - pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set)); - - FD_ZERO(PART_FDSET(fdsetp)); - PART_COUNT(fdsetp) = 0; -} - - -PJ_DEF(void) PJ_FD_SET(pj_sock_t fd, pj_fd_set_t *fdsetp) -{ - PJ_CHECK_STACK(); - pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set)); - - if (!PJ_FD_ISSET(fd, fdsetp)) - ++PART_COUNT(fdsetp); - FD_SET(fd, PART_FDSET(fdsetp)); -} - - -PJ_DEF(void) PJ_FD_CLR(pj_sock_t fd, pj_fd_set_t *fdsetp) -{ - PJ_CHECK_STACK(); - pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set)); - - if (PJ_FD_ISSET(fd, fdsetp)) - --PART_COUNT(fdsetp); - FD_CLR(fd, PART_FDSET(fdsetp)); -} - - -PJ_DEF(pj_bool_t) PJ_FD_ISSET(pj_sock_t fd, const pj_fd_set_t *fdsetp) -{ - PJ_CHECK_STACK(); - PJ_ASSERT_RETURN(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set), - 0); - - return FD_ISSET(fd, PART_FDSET(fdsetp)); -} - -PJ_DEF(pj_size_t) PJ_FD_COUNT(const pj_fd_set_t *fdsetp) -{ - return PART_COUNT(fdsetp); -} - -PJ_DEF(int) pj_sock_select( int n, - pj_fd_set_t *readfds, - pj_fd_set_t *writefds, - pj_fd_set_t *exceptfds, - const pj_time_val *timeout) -{ - struct timeval os_timeout, *p_os_timeout; - - PJ_CHECK_STACK(); - - PJ_ASSERT_RETURN(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set), - PJ_EBUG); - - if (timeout) { - os_timeout.tv_sec = timeout->sec; - os_timeout.tv_usec = timeout->msec * 1000; - p_os_timeout = &os_timeout; - } else { - p_os_timeout = NULL; - } - - return select(n, PART_FDSET(readfds), PART_FDSET(writefds), - PART_FDSET(exceptfds), p_os_timeout); -} - +/* $Header: /pjproject-0.3/pjlib/src/pj/sock_select.c 4 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/sock_select.c $ + * + * 4 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 3 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 2 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + * 1 9/15/05 8:40p Bennylp + * Created. + */ +#include +#include +#include +#include +#include + +#if defined(PJ_HAS_STRING_H) && PJ_HAS_STRING_H!=0 +# include +#endif + +#ifdef _MSC_VER +# pragma warning(disable: 4018) // Signed/unsigned mismatch in FD_* +#endif + +#define PART_FDSET(ps) ((fd_set*)&ps->data[1]) +#define PART_FDSET_OR_NULL(ps) (ps ? PART_FDSET(ps) : NULL) +#define PART_COUNT(ps) (ps->data[0]) + +PJ_DEF(void) PJ_FD_ZERO(pj_fd_set_t *fdsetp) +{ + PJ_CHECK_STACK(); + pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set)); + + FD_ZERO(PART_FDSET(fdsetp)); + PART_COUNT(fdsetp) = 0; +} + + +PJ_DEF(void) PJ_FD_SET(pj_sock_t fd, pj_fd_set_t *fdsetp) +{ + PJ_CHECK_STACK(); + pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set)); + + if (!PJ_FD_ISSET(fd, fdsetp)) + ++PART_COUNT(fdsetp); + FD_SET(fd, PART_FDSET(fdsetp)); +} + + +PJ_DEF(void) PJ_FD_CLR(pj_sock_t fd, pj_fd_set_t *fdsetp) +{ + PJ_CHECK_STACK(); + pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set)); + + if (PJ_FD_ISSET(fd, fdsetp)) + --PART_COUNT(fdsetp); + FD_CLR(fd, PART_FDSET(fdsetp)); +} + + +PJ_DEF(pj_bool_t) PJ_FD_ISSET(pj_sock_t fd, const pj_fd_set_t *fdsetp) +{ + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set), + 0); + + return FD_ISSET(fd, PART_FDSET(fdsetp)); +} + +PJ_DEF(pj_size_t) PJ_FD_COUNT(const pj_fd_set_t *fdsetp) +{ + return PART_COUNT(fdsetp); +} + +PJ_DEF(int) pj_sock_select( int n, + pj_fd_set_t *readfds, + pj_fd_set_t *writefds, + pj_fd_set_t *exceptfds, + const pj_time_val *timeout) +{ + struct timeval os_timeout, *p_os_timeout; + + PJ_CHECK_STACK(); + + PJ_ASSERT_RETURN(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set), + PJ_EBUG); + + if (timeout) { + os_timeout.tv_sec = timeout->sec; + os_timeout.tv_usec = timeout->msec * 1000; + p_os_timeout = &os_timeout; + } else { + p_os_timeout = NULL; + } + + return select(n, PART_FDSET_OR_NULL(readfds), PART_FDSET_OR_NULL(writefds), + PART_FDSET_OR_NULL(exceptfds), p_os_timeout); +} + diff --git a/pjlib/src/pj/string.c b/pjlib/src/pj/string.c index c3f1b5ff..3430b233 100644 --- a/pjlib/src/pj/string.c +++ b/pjlib/src/pj/string.c @@ -1,124 +1,124 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/string.c 9 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/string.c $ - * - * 9 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 8 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include -#include -#include - -#if PJ_FUNCTIONS_ARE_INLINED==0 -# include -#endif - - -static char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - -PJ_DEF(pj_str_t*) pj_strltrim( pj_str_t *str ) -{ - register char *p = str->ptr; - while (pj_isspace(*p)) - ++p; - str->slen -= (p - str->ptr); - str->ptr = p; - return str; -} - -PJ_DEF(pj_str_t*) pj_strrtrim( pj_str_t *str ) -{ - char *end = str->ptr + str->slen; - register char *p = end - 1; - while (p >= str->ptr && pj_isspace(*p)) - --p; - str->slen -= ((end - p) - 1); - return str; -} - -PJ_INLINE(void) pj_val_to_hex_digit(unsigned value, char *p) -{ - *p++ = hex[ (value & 0xF0) >> 4 ]; - *p++ = hex[ (value & 0x0F) ]; -} - -PJ_DEF(char*) pj_create_random_string(char *str, pj_size_t len) -{ - unsigned i; - char *p = str; - - PJ_CHECK_STACK(); - - for (i=0; i> 24, p+0 ); - pj_val_to_hex_digit( (val & 0x00FF0000) >> 16, p+2 ); - pj_val_to_hex_digit( (val & 0x0000FF00) >> 8, p+4 ); - pj_val_to_hex_digit( (val & 0x000000FF) >> 0, p+6 ); - p += 8; - } - for (i=i * 8; islen; ++i) { - value = value * 10 + (str->ptr[i] - '0'); - } - return value; -} - -PJ_DEF(int) pj_utoa(unsigned long val, char *buf) -{ - return pj_utoa_pad(val, buf, 0, 0); -} - -PJ_DEF(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad) -{ - char *p; - int len; - - PJ_CHECK_STACK(); - - p = buf; - do { - unsigned long digval = (unsigned long) (val % 10); - val /= 10; - *p++ = (char) (digval + '0'); - } while (val > 0); - - len = p-buf; - while (len < min_dig) { - *p++ = (char)pad; - ++len; - } - *p-- = '\0'; - - do { - char temp = *p; - *p = *buf; - *buf = temp; - --p; - ++buf; - } while (buf < p); - - return len; -} - +/* $Header: /pjproject-0.3/pjlib/src/pj/string.c 9 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/string.c $ + * + * 9 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 8 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include +#include +#include +#include + +#if PJ_FUNCTIONS_ARE_INLINED==0 +# include +#endif + + +static char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + +PJ_DEF(pj_str_t*) pj_strltrim( pj_str_t *str ) +{ + register char *p = str->ptr; + while (pj_isspace(*p)) + ++p; + str->slen -= (p - str->ptr); + str->ptr = p; + return str; +} + +PJ_DEF(pj_str_t*) pj_strrtrim( pj_str_t *str ) +{ + char *end = str->ptr + str->slen; + register char *p = end - 1; + while (p >= str->ptr && pj_isspace(*p)) + --p; + str->slen -= ((end - p) - 1); + return str; +} + +PJ_INLINE(void) pj_val_to_hex_digit(unsigned value, char *p) +{ + *p++ = hex[ (value & 0xF0) >> 4 ]; + *p++ = hex[ (value & 0x0F) ]; +} + +PJ_DEF(char*) pj_create_random_string(char *str, pj_size_t len) +{ + unsigned i; + char *p = str; + + PJ_CHECK_STACK(); + + for (i=0; i> 24, p+0 ); + pj_val_to_hex_digit( (val & 0x00FF0000) >> 16, p+2 ); + pj_val_to_hex_digit( (val & 0x0000FF00) >> 8, p+4 ); + pj_val_to_hex_digit( (val & 0x000000FF) >> 0, p+6 ); + p += 8; + } + for (i=i * 8; islen; ++i) { + value = value * 10 + (str->ptr[i] - '0'); + } + return value; +} + +PJ_DEF(int) pj_utoa(unsigned long val, char *buf) +{ + return pj_utoa_pad(val, buf, 0, 0); +} + +PJ_DEF(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad) +{ + char *p; + int len; + + PJ_CHECK_STACK(); + + p = buf; + do { + unsigned long digval = (unsigned long) (val % 10); + val /= 10; + *p++ = (char) (digval + '0'); + } while (val > 0); + + len = p-buf; + while (len < min_dig) { + *p++ = (char)pad; + ++len; + } + *p-- = '\0'; + + do { + char temp = *p; + *p = *buf; + *buf = temp; + --p; + ++buf; + } while (buf < p); + + return len; +} + diff --git a/pjlib/src/pj/stun.c b/pjlib/src/pj/stun.c index efd43560..670ceefc 100644 --- a/pjlib/src/pj/stun.c +++ b/pjlib/src/pj/stun.c @@ -1,118 +1,118 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/stun.c 6 9/17/05 10:37a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/stun.c $ - * - * 6 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include -#include -#include - -#define THIS_FILE "stun" - -PJ_DEF(pj_status_t) pj_stun_create_bind_req( pj_pool_t *pool, - void **msg, pj_size_t *len, - pj_uint32_t id_hi, - pj_uint32_t id_lo) -{ - pj_stun_msg_hdr *hdr; - - PJ_CHECK_STACK(); - - PJ_LOG(5,(THIS_FILE, "pj_stun_create_bind_req")); - - hdr = pj_pool_calloc(pool, 1, sizeof(pj_stun_msg_hdr)); - if (!hdr) { - PJ_LOG(5,(THIS_FILE, "Error allocating memory!")); - return -1; - } - - hdr->type = pj_htons(PJ_STUN_BINDING_REQUEST); - hdr->tsx[2] = pj_htonl(id_hi); - hdr->tsx[3] = pj_htonl(id_lo); - *msg = hdr; - *len = sizeof(pj_stun_msg_hdr); - - return 0; -} - -PJ_DEF(pj_status_t) pj_stun_parse_msg( void *buf, pj_size_t len, - pj_stun_msg *msg) -{ - pj_uint16_t msg_type, msg_len; - char *p_attr; - - PJ_CHECK_STACK(); - - PJ_LOG(5,(THIS_FILE, "pj_stun_parse_msg %p, len=%d", buf, len)); - - msg->hdr = (pj_stun_msg_hdr*)buf; - msg_type = pj_ntohs(msg->hdr->type); - - switch (msg_type) { - case PJ_STUN_BINDING_REQUEST: - case PJ_STUN_BINDING_RESPONSE: - case PJ_STUN_BINDING_ERROR_RESPONSE: - case PJ_STUN_SHARED_SECRET_REQUEST: - case PJ_STUN_SHARED_SECRET_RESPONSE: - case PJ_STUN_SHARED_SECRET_ERROR_RESPONSE: - break; - default: - PJ_LOG(5,(THIS_FILE, "Error: unknown msg type %d", msg_type)); - return -1; - } - - msg_len = pj_ntohs(msg->hdr->length); - if (msg_len != len - sizeof(pj_stun_msg_hdr)) { - PJ_LOG(5,(THIS_FILE, "Error: invalid msg_len %d (expecting %d)", - msg_len, len - sizeof(pj_stun_msg_hdr))); - return -1; - } - - msg->attr_count = 0; - p_attr = (char*)buf + sizeof(pj_stun_msg_hdr); - - while (msg_len > 0) { - pj_stun_attr_hdr **attr = &msg->attr[msg->attr_count]; - pj_uint32_t len; - - *attr = (pj_stun_attr_hdr*)p_attr; - len = pj_ntohs((pj_uint16_t) ((*attr)->length)) + sizeof(pj_stun_attr_hdr); - - if (msg_len < len) { - PJ_LOG(5,(THIS_FILE, "Error: length mismatch in attr %d", - msg->attr_count)); - return -1; - } - - if (pj_ntohs((*attr)->type) > PJ_STUN_ATTR_REFLECTED_FORM) { - PJ_LOG(5,(THIS_FILE, "Error: invalid attr type %d in attr %d", - pj_ntohs((*attr)->type), msg->attr_count)); - return -1; - } - - msg_len = (pj_uint16_t)(msg_len - len); - p_attr += len; - ++msg->attr_count; - } - - return 0; -} - -PJ_DEF(void*) pj_stun_msg_find_attr( pj_stun_msg *msg, pj_stun_attr_type t) -{ - int i; - - PJ_CHECK_STACK(); - - for (i=0; iattr_count; ++i) { - pj_stun_attr_hdr *attr = msg->attr[i]; - if (pj_ntohs(attr->type) == t) - return attr; - } - - return 0; -} +/* $Header: /pjproject-0.3/pjlib/src/pj/stun.c 6 9/17/05 10:37a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/stun.c $ + * + * 6 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include +#include +#include +#include + +#define THIS_FILE "stun" + +PJ_DEF(pj_status_t) pj_stun_create_bind_req( pj_pool_t *pool, + void **msg, pj_size_t *len, + pj_uint32_t id_hi, + pj_uint32_t id_lo) +{ + pj_stun_msg_hdr *hdr; + + PJ_CHECK_STACK(); + + PJ_LOG(5,(THIS_FILE, "pj_stun_create_bind_req")); + + hdr = pj_pool_calloc(pool, 1, sizeof(pj_stun_msg_hdr)); + if (!hdr) { + PJ_LOG(5,(THIS_FILE, "Error allocating memory!")); + return -1; + } + + hdr->type = pj_htons(PJ_STUN_BINDING_REQUEST); + hdr->tsx[2] = pj_htonl(id_hi); + hdr->tsx[3] = pj_htonl(id_lo); + *msg = hdr; + *len = sizeof(pj_stun_msg_hdr); + + return 0; +} + +PJ_DEF(pj_status_t) pj_stun_parse_msg( void *buf, pj_size_t len, + pj_stun_msg *msg) +{ + pj_uint16_t msg_type, msg_len; + char *p_attr; + + PJ_CHECK_STACK(); + + PJ_LOG(5,(THIS_FILE, "pj_stun_parse_msg %p, len=%d", buf, len)); + + msg->hdr = (pj_stun_msg_hdr*)buf; + msg_type = pj_ntohs(msg->hdr->type); + + switch (msg_type) { + case PJ_STUN_BINDING_REQUEST: + case PJ_STUN_BINDING_RESPONSE: + case PJ_STUN_BINDING_ERROR_RESPONSE: + case PJ_STUN_SHARED_SECRET_REQUEST: + case PJ_STUN_SHARED_SECRET_RESPONSE: + case PJ_STUN_SHARED_SECRET_ERROR_RESPONSE: + break; + default: + PJ_LOG(5,(THIS_FILE, "Error: unknown msg type %d", msg_type)); + return -1; + } + + msg_len = pj_ntohs(msg->hdr->length); + if (msg_len != len - sizeof(pj_stun_msg_hdr)) { + PJ_LOG(5,(THIS_FILE, "Error: invalid msg_len %d (expecting %d)", + msg_len, len - sizeof(pj_stun_msg_hdr))); + return -1; + } + + msg->attr_count = 0; + p_attr = (char*)buf + sizeof(pj_stun_msg_hdr); + + while (msg_len > 0) { + pj_stun_attr_hdr **attr = &msg->attr[msg->attr_count]; + pj_uint32_t len; + + *attr = (pj_stun_attr_hdr*)p_attr; + len = pj_ntohs((pj_uint16_t) ((*attr)->length)) + sizeof(pj_stun_attr_hdr); + + if (msg_len < len) { + PJ_LOG(5,(THIS_FILE, "Error: length mismatch in attr %d", + msg->attr_count)); + return -1; + } + + if (pj_ntohs((*attr)->type) > PJ_STUN_ATTR_REFLECTED_FORM) { + PJ_LOG(5,(THIS_FILE, "Error: invalid attr type %d in attr %d", + pj_ntohs((*attr)->type), msg->attr_count)); + return -1; + } + + msg_len = (pj_uint16_t)(msg_len - len); + p_attr += len; + ++msg->attr_count; + } + + return 0; +} + +PJ_DEF(void*) pj_stun_msg_find_attr( pj_stun_msg *msg, pj_stun_attr_type t) +{ + int i; + + PJ_CHECK_STACK(); + + for (i=0; iattr_count; ++i) { + pj_stun_attr_hdr *attr = msg->attr[i]; + if (pj_ntohs(attr->type) == t) + return attr; + } + + return 0; +} diff --git a/pjlib/src/pj/stun_client.c b/pjlib/src/pj/stun_client.c index c35a8541..bc9b6f35 100644 --- a/pjlib/src/pj/stun_client.c +++ b/pjlib/src/pj/stun_client.c @@ -1,270 +1,270 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/stun_client.c 6 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/stun_client.c $ - * - * 6 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 5 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include -#include -#include -#include - -enum { MAX_REQUEST = 3 }; -static int stun_timer[] = {1600, 1600, 1600 }; - -#define THIS_FILE "stunclient" -#define LOG_ADDR(addr) pj_inet_ntoa(addr.sin_addr), pj_ntohs(addr.sin_port) - - -PJ_DECL(pj_status_t) pj_stun_get_mapped_addr( pj_pool_factory *pf, - int sock_cnt, pj_sock_t sock[], - const pj_str_t *srv1, int port1, - const pj_str_t *srv2, int port2, - pj_sockaddr_in mapped_addr[]) -{ - pj_sockaddr_in srv_addr[2]; - int i, j, rc, send_cnt = 0; - pj_pool_t *pool; - struct { - struct { - pj_uint32_t mapped_addr; - pj_uint32_t mapped_port; - } srv[2]; - } *rec; - void *out_msg; - pj_size_t out_msg_len; - int wait_resp = 0; - int mapped_status = 0; - - PJ_CHECK_STACK(); - - /* Create pool. */ - pool = pj_pool_create(pf, "stun%p", 1024, 1024, NULL); - if (!pool) { - mapped_status = PJ_STUN_ERR_MEMORY; - return -1; - } - - /* Allocate client records */ - rec = pj_pool_calloc(pool, sock_cnt, sizeof(*rec)); - if (!rec) { - mapped_status = PJ_STUN_ERR_MEMORY; - goto on_error; - } - - /* Create the outgoing BIND REQUEST message template */ - rc = pj_stun_create_bind_req( pool, &out_msg, &out_msg_len, 0, 0); - if (rc != 0) { - mapped_status = -1; - goto on_error; - } - - /* Resolve servers. */ - if (pj_sockaddr_in_init(&srv_addr[0], srv1, (pj_uint16_t)port1) != 0) { - mapped_status = PJ_STUN_ERR_RESOLVE; - goto on_error; - } - if (pj_sockaddr_in_init(&srv_addr[1], srv2, (pj_uint16_t)port2) != 0) { - mapped_status = PJ_STUN_ERR_RESOLVE; - goto on_error; - } - - /* Init mapped addresses to zero */ - pj_memset(mapped_addr, 0, sock_cnt * sizeof(pj_sockaddr_in)); - - /* Main retransmission loop. */ - for (send_cnt=0; send_cnttsx[2] = pj_htonl(i); - msg_hdr->tsx[3] = pj_htonl(j); - - /* Send! */ - sent_len = out_msg_len; - rc = pj_sock_sendto(sock[i], out_msg, &sent_len, 0, - (pj_sockaddr_t*)&srv_addr[j], - sizeof(pj_sockaddr_in)); - if (sent_len != (int)out_msg_len) { - PJ_LOG(4,(THIS_FILE, - "Error sending STUN request to %s:%d", - LOG_ADDR(srv_addr[j]))); - mapped_status = PJ_STUN_ERR_TRANSPORT; - } else { - ++wait_resp; - } - } - } - - /* All requests sent. - * The loop below will wait for responses until all responses have - * been received (i.e. wait_resp==0) or timeout occurs, which then - * we'll go to the next retransmission iteration. - */ - - /* Calculate time of next retransmission. */ - pj_gettimeofday(&next_tx); - next_tx.sec += (stun_timer[send_cnt]/1000); - next_tx.msec += (stun_timer[send_cnt]%1000); - pj_time_val_normalize(&next_tx); - - for (pj_gettimeofday(&now), select_rc=1; - mapped_status==0 && select_rc==1 && wait_resp>0 && PJ_TIME_VAL_LT(now, next_tx); - pj_gettimeofday(&now)) - { - pj_time_val timeout; - - timeout = next_tx; - PJ_TIME_VAL_SUB(timeout, now); - - for (i=0; itsx[2]); - srv_idx = pj_ntohl(msg.hdr->tsx[3]); - - if (sock_idx<0 || sock_idx>=sock_cnt || srv_idx<0 || srv_idx>=2) { - PJ_LOG(4,(THIS_FILE, - "Invalid transaction ID from %s:%d", - LOG_ADDR(addr))); - mapped_status = PJ_STUN_ERR_INVALID_MSG; - continue; - } - - if (pj_ntohs(msg.hdr->type) != PJ_STUN_BINDING_RESPONSE) { - PJ_LOG(4,(THIS_FILE, - "Non binding response %d from %s:%d", - pj_ntohs(msg.hdr->type), LOG_ADDR(addr))); - mapped_status = PJ_STUN_ERR_INVALID_MSG; - continue; - } - - if (pj_stun_msg_find_attr(&msg, PJ_STUN_ATTR_ERROR_CODE) != NULL) { - PJ_LOG(4,(THIS_FILE, - "Got STUN error attribute from %s:%d", - LOG_ADDR(addr))); - mapped_status = PJ_STUN_ERR_INVALID_MSG; - continue; - } - - attr = (void*)pj_stun_msg_find_attr(&msg, PJ_STUN_ATTR_MAPPED_ADDR); - if (!attr) { - PJ_LOG(4,(THIS_FILE, - "No mapped address in response from %s:%d", - LOG_ADDR(addr))); - mapped_status = PJ_STUN_ERR_INVALID_MSG; - continue; - } - - rec[sock_idx].srv[srv_idx].mapped_addr = attr->addr; - rec[sock_idx].srv[srv_idx].mapped_port = attr->port; - } - } - - /* The best scenario is if all requests have been replied. - * Then we don't need to go to the next retransmission iteration. - */ - if (wait_resp <= 0) - break; - } - - for (i=0; i +#include +#include +#include +#include +#include + +enum { MAX_REQUEST = 3 }; +static int stun_timer[] = {1600, 1600, 1600 }; + +#define THIS_FILE "stunclient" +#define LOG_ADDR(addr) pj_inet_ntoa(addr.sin_addr), pj_ntohs(addr.sin_port) + + +PJ_DECL(pj_status_t) pj_stun_get_mapped_addr( pj_pool_factory *pf, + int sock_cnt, pj_sock_t sock[], + const pj_str_t *srv1, int port1, + const pj_str_t *srv2, int port2, + pj_sockaddr_in mapped_addr[]) +{ + pj_sockaddr_in srv_addr[2]; + int i, j, rc, send_cnt = 0; + pj_pool_t *pool; + struct { + struct { + pj_uint32_t mapped_addr; + pj_uint32_t mapped_port; + } srv[2]; + } *rec; + void *out_msg; + pj_size_t out_msg_len; + int wait_resp = 0; + int mapped_status = 0; + + PJ_CHECK_STACK(); + + /* Create pool. */ + pool = pj_pool_create(pf, "stun%p", 1024, 1024, NULL); + if (!pool) { + mapped_status = PJ_STUN_ERR_MEMORY; + return -1; + } + + /* Allocate client records */ + rec = pj_pool_calloc(pool, sock_cnt, sizeof(*rec)); + if (!rec) { + mapped_status = PJ_STUN_ERR_MEMORY; + goto on_error; + } + + /* Create the outgoing BIND REQUEST message template */ + rc = pj_stun_create_bind_req( pool, &out_msg, &out_msg_len, 0, 0); + if (rc != 0) { + mapped_status = -1; + goto on_error; + } + + /* Resolve servers. */ + if (pj_sockaddr_in_init(&srv_addr[0], srv1, (pj_uint16_t)port1) != 0) { + mapped_status = PJ_STUN_ERR_RESOLVE; + goto on_error; + } + if (pj_sockaddr_in_init(&srv_addr[1], srv2, (pj_uint16_t)port2) != 0) { + mapped_status = PJ_STUN_ERR_RESOLVE; + goto on_error; + } + + /* Init mapped addresses to zero */ + pj_memset(mapped_addr, 0, sock_cnt * sizeof(pj_sockaddr_in)); + + /* Main retransmission loop. */ + for (send_cnt=0; send_cnttsx[2] = pj_htonl(i); + msg_hdr->tsx[3] = pj_htonl(j); + + /* Send! */ + sent_len = out_msg_len; + rc = pj_sock_sendto(sock[i], out_msg, &sent_len, 0, + (pj_sockaddr_t*)&srv_addr[j], + sizeof(pj_sockaddr_in)); + if (sent_len != (int)out_msg_len) { + PJ_LOG(4,(THIS_FILE, + "Error sending STUN request to %s:%d", + LOG_ADDR(srv_addr[j]))); + mapped_status = PJ_STUN_ERR_TRANSPORT; + } else { + ++wait_resp; + } + } + } + + /* All requests sent. + * The loop below will wait for responses until all responses have + * been received (i.e. wait_resp==0) or timeout occurs, which then + * we'll go to the next retransmission iteration. + */ + + /* Calculate time of next retransmission. */ + pj_gettimeofday(&next_tx); + next_tx.sec += (stun_timer[send_cnt]/1000); + next_tx.msec += (stun_timer[send_cnt]%1000); + pj_time_val_normalize(&next_tx); + + for (pj_gettimeofday(&now), select_rc=1; + mapped_status==0 && select_rc==1 && wait_resp>0 && PJ_TIME_VAL_LT(now, next_tx); + pj_gettimeofday(&now)) + { + pj_time_val timeout; + + timeout = next_tx; + PJ_TIME_VAL_SUB(timeout, now); + + for (i=0; itsx[2]); + srv_idx = pj_ntohl(msg.hdr->tsx[3]); + + if (sock_idx<0 || sock_idx>=sock_cnt || srv_idx<0 || srv_idx>=2) { + PJ_LOG(4,(THIS_FILE, + "Invalid transaction ID from %s:%d", + LOG_ADDR(addr))); + mapped_status = PJ_STUN_ERR_INVALID_MSG; + continue; + } + + if (pj_ntohs(msg.hdr->type) != PJ_STUN_BINDING_RESPONSE) { + PJ_LOG(4,(THIS_FILE, + "Non binding response %d from %s:%d", + pj_ntohs(msg.hdr->type), LOG_ADDR(addr))); + mapped_status = PJ_STUN_ERR_INVALID_MSG; + continue; + } + + if (pj_stun_msg_find_attr(&msg, PJ_STUN_ATTR_ERROR_CODE) != NULL) { + PJ_LOG(4,(THIS_FILE, + "Got STUN error attribute from %s:%d", + LOG_ADDR(addr))); + mapped_status = PJ_STUN_ERR_INVALID_MSG; + continue; + } + + attr = (void*)pj_stun_msg_find_attr(&msg, PJ_STUN_ATTR_MAPPED_ADDR); + if (!attr) { + PJ_LOG(4,(THIS_FILE, + "No mapped address in response from %s:%d", + LOG_ADDR(addr))); + mapped_status = PJ_STUN_ERR_INVALID_MSG; + continue; + } + + rec[sock_idx].srv[srv_idx].mapped_addr = attr->addr; + rec[sock_idx].srv[srv_idx].mapped_port = attr->port; + } + } + + /* The best scenario is if all requests have been replied. + * Then we don't need to go to the next retransmission iteration. + */ + if (wait_resp <= 0) + break; + } + + for (i=0; i - -/* - * addr_resolv.h - */ -PJ_EXPORT_SYMBOL(pj_gethostbyname) - -/* - * array.h - */ -PJ_EXPORT_SYMBOL(pj_array_insert) -PJ_EXPORT_SYMBOL(pj_array_erase) -PJ_EXPORT_SYMBOL(pj_array_find) - -/* - * config.h - */ -PJ_EXPORT_SYMBOL(pj_dump_config) - -/* - * errno.h - */ -PJ_EXPORT_SYMBOL(pj_get_os_error) -PJ_EXPORT_SYMBOL(pj_set_os_error) -PJ_EXPORT_SYMBOL(pj_get_netos_error) -PJ_EXPORT_SYMBOL(pj_set_netos_error) -PJ_EXPORT_SYMBOL(pj_strerror) - -/* - * except.h - */ -PJ_EXPORT_SYMBOL(pj_throw_exception_) -PJ_EXPORT_SYMBOL(pj_push_exception_handler_) -PJ_EXPORT_SYMBOL(pj_pop_exception_handler_) -PJ_EXPORT_SYMBOL(pj_setjmp) -PJ_EXPORT_SYMBOL(pj_longjmp) -PJ_EXPORT_SYMBOL(pj_exception_id_alloc) -PJ_EXPORT_SYMBOL(pj_exception_id_free) -PJ_EXPORT_SYMBOL(pj_exception_id_name) - - -/* - * fifobuf.h - */ -PJ_EXPORT_SYMBOL(pj_fifobuf_init) -PJ_EXPORT_SYMBOL(pj_fifobuf_max_size) -PJ_EXPORT_SYMBOL(pj_fifobuf_alloc) -PJ_EXPORT_SYMBOL(pj_fifobuf_unalloc) -PJ_EXPORT_SYMBOL(pj_fifobuf_free) - -/* - * guid.h - */ -PJ_EXPORT_SYMBOL(pj_generate_unique_string) -PJ_EXPORT_SYMBOL(pj_create_unique_string) - -/* - * hash.h - */ -PJ_EXPORT_SYMBOL(pj_hash_calc) -PJ_EXPORT_SYMBOL(pj_hash_create) -PJ_EXPORT_SYMBOL(pj_hash_get) -PJ_EXPORT_SYMBOL(pj_hash_set) -PJ_EXPORT_SYMBOL(pj_hash_count) -PJ_EXPORT_SYMBOL(pj_hash_first) -PJ_EXPORT_SYMBOL(pj_hash_next) -PJ_EXPORT_SYMBOL(pj_hash_this) - -/* - * ioqueue.h - */ -PJ_EXPORT_SYMBOL(pj_ioqueue_create) -PJ_EXPORT_SYMBOL(pj_ioqueue_destroy) -PJ_EXPORT_SYMBOL(pj_ioqueue_set_lock) -PJ_EXPORT_SYMBOL(pj_ioqueue_register_sock) -PJ_EXPORT_SYMBOL(pj_ioqueue_unregister) -PJ_EXPORT_SYMBOL(pj_ioqueue_get_user_data) -PJ_EXPORT_SYMBOL(pj_ioqueue_poll) -PJ_EXPORT_SYMBOL(pj_ioqueue_read) -PJ_EXPORT_SYMBOL(pj_ioqueue_recv) -PJ_EXPORT_SYMBOL(pj_ioqueue_recvfrom) -PJ_EXPORT_SYMBOL(pj_ioqueue_write) -PJ_EXPORT_SYMBOL(pj_ioqueue_send) -PJ_EXPORT_SYMBOL(pj_ioqueue_sendto) -#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 -PJ_EXPORT_SYMBOL(pj_ioqueue_accept) -PJ_EXPORT_SYMBOL(pj_ioqueue_connect) -#endif - -/* - * list.h - */ -PJ_EXPORT_SYMBOL(pj_list_insert_before) -PJ_EXPORT_SYMBOL(pj_list_insert_nodes_before) -PJ_EXPORT_SYMBOL(pj_list_insert_after) -PJ_EXPORT_SYMBOL(pj_list_insert_nodes_after) -PJ_EXPORT_SYMBOL(pj_list_merge_first) -PJ_EXPORT_SYMBOL(pj_list_merge_last) -PJ_EXPORT_SYMBOL(pj_list_erase) -PJ_EXPORT_SYMBOL(pj_list_find_node) -PJ_EXPORT_SYMBOL(pj_list_search) - - -/* - * log.h - */ -PJ_EXPORT_SYMBOL(pj_log_write) -#if PJ_LOG_MAX_LEVEL >= 1 -PJ_EXPORT_SYMBOL(pj_log_set_log_func) -PJ_EXPORT_SYMBOL(pj_log_get_log_func) -PJ_EXPORT_SYMBOL(pj_log_set_level) -PJ_EXPORT_SYMBOL(pj_log_get_level) -PJ_EXPORT_SYMBOL(pj_log_set_decor) -PJ_EXPORT_SYMBOL(pj_log_get_decor) -PJ_EXPORT_SYMBOL(pj_log_1) -#endif -#if PJ_LOG_MAX_LEVEL >= 2 -PJ_EXPORT_SYMBOL(pj_log_2) -#endif -#if PJ_LOG_MAX_LEVEL >= 3 -PJ_EXPORT_SYMBOL(pj_log_3) -#endif -#if PJ_LOG_MAX_LEVEL >= 4 -PJ_EXPORT_SYMBOL(pj_log_4) -#endif -#if PJ_LOG_MAX_LEVEL >= 5 -PJ_EXPORT_SYMBOL(pj_log_5) -#endif -#if PJ_LOG_MAX_LEVEL >= 6 -PJ_EXPORT_SYMBOL(pj_log_6) -#endif - -/* - * md5.h - */ -PJ_EXPORT_SYMBOL(md5_init) -PJ_EXPORT_SYMBOL(md5_append) -PJ_EXPORT_SYMBOL(md5_finish) - - -/* - * os.h - */ -PJ_EXPORT_SYMBOL(pj_init) -PJ_EXPORT_SYMBOL(pj_getpid) -PJ_EXPORT_SYMBOL(pj_thread_register) -PJ_EXPORT_SYMBOL(pj_thread_create) -PJ_EXPORT_SYMBOL(pj_thread_get_name) -PJ_EXPORT_SYMBOL(pj_thread_resume) -PJ_EXPORT_SYMBOL(pj_thread_this) -PJ_EXPORT_SYMBOL(pj_thread_join) -PJ_EXPORT_SYMBOL(pj_thread_destroy) -PJ_EXPORT_SYMBOL(pj_thread_sleep) -#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0 -PJ_EXPORT_SYMBOL(pj_thread_check_stack) -PJ_EXPORT_SYMBOL(pj_thread_get_stack_max_usage) -PJ_EXPORT_SYMBOL(pj_thread_get_stack_info) -#endif -PJ_EXPORT_SYMBOL(pj_atomic_create) -PJ_EXPORT_SYMBOL(pj_atomic_destroy) -PJ_EXPORT_SYMBOL(pj_atomic_set) -PJ_EXPORT_SYMBOL(pj_atomic_get) -PJ_EXPORT_SYMBOL(pj_atomic_inc) -PJ_EXPORT_SYMBOL(pj_atomic_dec) -PJ_EXPORT_SYMBOL(pj_thread_local_alloc) -PJ_EXPORT_SYMBOL(pj_thread_local_free) -PJ_EXPORT_SYMBOL(pj_thread_local_set) -PJ_EXPORT_SYMBOL(pj_thread_local_get) -PJ_EXPORT_SYMBOL(pj_enter_critical_section) -PJ_EXPORT_SYMBOL(pj_leave_critical_section) -PJ_EXPORT_SYMBOL(pj_mutex_create) -PJ_EXPORT_SYMBOL(pj_mutex_lock) -PJ_EXPORT_SYMBOL(pj_mutex_unlock) -PJ_EXPORT_SYMBOL(pj_mutex_trylock) -PJ_EXPORT_SYMBOL(pj_mutex_destroy) -#if defined(PJ_DEBUG) && PJ_DEBUG != 0 -PJ_EXPORT_SYMBOL(pj_mutex_is_locked) -#endif -#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 -PJ_EXPORT_SYMBOL(pj_sem_create) -PJ_EXPORT_SYMBOL(pj_sem_wait) -PJ_EXPORT_SYMBOL(pj_sem_trywait) -PJ_EXPORT_SYMBOL(pj_sem_post) -PJ_EXPORT_SYMBOL(pj_sem_destroy) -#endif -PJ_EXPORT_SYMBOL(pj_gettimeofday) -PJ_EXPORT_SYMBOL(pj_time_decode) -#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0 -PJ_EXPORT_SYMBOL(pj_get_timestamp) -PJ_EXPORT_SYMBOL(pj_get_timestamp_freq) -PJ_EXPORT_SYMBOL(pj_elapsed_time) -PJ_EXPORT_SYMBOL(pj_elapsed_usec) -PJ_EXPORT_SYMBOL(pj_elapsed_nanosec) -PJ_EXPORT_SYMBOL(pj_elapsed_cycle) -#endif - - -/* - * pool.h - */ -PJ_EXPORT_SYMBOL(pj_pool_create) -PJ_EXPORT_SYMBOL(pj_pool_release) -PJ_EXPORT_SYMBOL(pj_pool_getobjname) -PJ_EXPORT_SYMBOL(pj_pool_reset) -PJ_EXPORT_SYMBOL(pj_pool_get_capacity) -PJ_EXPORT_SYMBOL(pj_pool_get_used_size) -PJ_EXPORT_SYMBOL(pj_pool_alloc) -PJ_EXPORT_SYMBOL(pj_pool_calloc) -PJ_EXPORT_SYMBOL(pj_pool_factory_default_policy) -PJ_EXPORT_SYMBOL(pj_pool_create_int) -PJ_EXPORT_SYMBOL(pj_pool_init_int) -PJ_EXPORT_SYMBOL(pj_pool_destroy_int) -PJ_EXPORT_SYMBOL(pj_caching_pool_init) -PJ_EXPORT_SYMBOL(pj_caching_pool_destroy) - -/* - * rand.h - */ -PJ_EXPORT_SYMBOL(pj_rand) -PJ_EXPORT_SYMBOL(pj_srand) - -/* - * rbtree.h - */ -PJ_EXPORT_SYMBOL(pj_rbtree_init) -PJ_EXPORT_SYMBOL(pj_rbtree_first) -PJ_EXPORT_SYMBOL(pj_rbtree_last) -PJ_EXPORT_SYMBOL(pj_rbtree_next) -PJ_EXPORT_SYMBOL(pj_rbtree_prev) -PJ_EXPORT_SYMBOL(pj_rbtree_insert) -PJ_EXPORT_SYMBOL(pj_rbtree_find) -PJ_EXPORT_SYMBOL(pj_rbtree_erase) -PJ_EXPORT_SYMBOL(pj_rbtree_max_height) -PJ_EXPORT_SYMBOL(pj_rbtree_min_height) - -/* - * scanner.h - */ -PJ_EXPORT_SYMBOL(pj_cs_init) -PJ_EXPORT_SYMBOL(pj_cs_set) -PJ_EXPORT_SYMBOL(pj_cs_add_range) -PJ_EXPORT_SYMBOL(pj_cs_add_alpha) -PJ_EXPORT_SYMBOL(pj_cs_add_num) -PJ_EXPORT_SYMBOL(pj_cs_add_str) -PJ_EXPORT_SYMBOL(pj_cs_del_range) -PJ_EXPORT_SYMBOL(pj_cs_del_str) -PJ_EXPORT_SYMBOL(pj_cs_invert) -PJ_EXPORT_SYMBOL(pj_scan_init) -PJ_EXPORT_SYMBOL(pj_scan_fini) -PJ_EXPORT_SYMBOL(pj_scan_peek) -PJ_EXPORT_SYMBOL(pj_scan_peek_n) -PJ_EXPORT_SYMBOL(pj_scan_peek_until) -PJ_EXPORT_SYMBOL(pj_scan_get) -PJ_EXPORT_SYMBOL(pj_scan_get_quote) -PJ_EXPORT_SYMBOL(pj_scan_get_n) -PJ_EXPORT_SYMBOL(pj_scan_get_char) -PJ_EXPORT_SYMBOL(pj_scan_get_newline) -PJ_EXPORT_SYMBOL(pj_scan_get_until) -PJ_EXPORT_SYMBOL(pj_scan_get_until_ch) -PJ_EXPORT_SYMBOL(pj_scan_get_until_chr) -PJ_EXPORT_SYMBOL(pj_scan_advance_n) -PJ_EXPORT_SYMBOL(pj_scan_strcmp) -PJ_EXPORT_SYMBOL(pj_scan_stricmp) -PJ_EXPORT_SYMBOL(pj_scan_skip_whitespace) -PJ_EXPORT_SYMBOL(pj_scan_save_state) -PJ_EXPORT_SYMBOL(pj_scan_restore_state) - -/* - * sock.h - */ -PJ_EXPORT_SYMBOL(PJ_AF_UNIX) -PJ_EXPORT_SYMBOL(PJ_AF_INET) -PJ_EXPORT_SYMBOL(PJ_AF_INET6) -PJ_EXPORT_SYMBOL(PJ_AF_PACKET) -PJ_EXPORT_SYMBOL(PJ_AF_IRDA) -PJ_EXPORT_SYMBOL(PJ_SOCK_STREAM) -PJ_EXPORT_SYMBOL(PJ_SOCK_DGRAM) -PJ_EXPORT_SYMBOL(PJ_SOCK_RAW) -PJ_EXPORT_SYMBOL(PJ_SOCK_RDM) -PJ_EXPORT_SYMBOL(PJ_SOL_SOCKET) -PJ_EXPORT_SYMBOL(PJ_SOL_IP) -PJ_EXPORT_SYMBOL(PJ_SOL_TCP) -PJ_EXPORT_SYMBOL(PJ_SOL_UDP) -PJ_EXPORT_SYMBOL(PJ_SOL_IPV6) -PJ_EXPORT_SYMBOL(pj_ntohs) -PJ_EXPORT_SYMBOL(pj_htons) -PJ_EXPORT_SYMBOL(pj_ntohl) -PJ_EXPORT_SYMBOL(pj_htonl) -PJ_EXPORT_SYMBOL(pj_inet_ntoa) -PJ_EXPORT_SYMBOL(pj_inet_aton) -PJ_EXPORT_SYMBOL(pj_inet_addr) -PJ_EXPORT_SYMBOL(pj_sockaddr_in_set_str_addr) -PJ_EXPORT_SYMBOL(pj_sockaddr_in_init) -PJ_EXPORT_SYMBOL(pj_gethostname) -PJ_EXPORT_SYMBOL(pj_gethostaddr) -PJ_EXPORT_SYMBOL(pj_sock_socket) -PJ_EXPORT_SYMBOL(pj_sock_close) -PJ_EXPORT_SYMBOL(pj_sock_bind) -PJ_EXPORT_SYMBOL(pj_sock_bind_in) -#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 -PJ_EXPORT_SYMBOL(pj_sock_listen) -PJ_EXPORT_SYMBOL(pj_sock_accept) -PJ_EXPORT_SYMBOL(pj_sock_shutdown) -#endif -PJ_EXPORT_SYMBOL(pj_sock_connect) -PJ_EXPORT_SYMBOL(pj_sock_getpeername) -PJ_EXPORT_SYMBOL(pj_sock_getsockname) -PJ_EXPORT_SYMBOL(pj_sock_getsockopt) -PJ_EXPORT_SYMBOL(pj_sock_setsockopt) -PJ_EXPORT_SYMBOL(pj_sock_recv) -PJ_EXPORT_SYMBOL(pj_sock_recvfrom) -PJ_EXPORT_SYMBOL(pj_sock_send) -PJ_EXPORT_SYMBOL(pj_sock_sendto) - -/* - * sock_select.h - */ -PJ_EXPORT_SYMBOL(PJ_FD_ZERO) -PJ_EXPORT_SYMBOL(PJ_FD_SET) -PJ_EXPORT_SYMBOL(PJ_FD_CLR) -PJ_EXPORT_SYMBOL(PJ_FD_ISSET) -PJ_EXPORT_SYMBOL(pj_sock_select) - -/* - * string.h - */ -PJ_EXPORT_SYMBOL(pj_str) -PJ_EXPORT_SYMBOL(pj_strassign) -PJ_EXPORT_SYMBOL(pj_strcpy) -PJ_EXPORT_SYMBOL(pj_strcpy2) -PJ_EXPORT_SYMBOL(pj_strdup) -PJ_EXPORT_SYMBOL(pj_strdup_with_null) -PJ_EXPORT_SYMBOL(pj_strdup2) -PJ_EXPORT_SYMBOL(pj_strdup3) -PJ_EXPORT_SYMBOL(pj_strcmp) -PJ_EXPORT_SYMBOL(pj_strcmp2) -PJ_EXPORT_SYMBOL(pj_strncmp) -PJ_EXPORT_SYMBOL(pj_strncmp2) -PJ_EXPORT_SYMBOL(pj_stricmp) -PJ_EXPORT_SYMBOL(pj_stricmp2) -PJ_EXPORT_SYMBOL(pj_strnicmp) -PJ_EXPORT_SYMBOL(pj_strnicmp2) -PJ_EXPORT_SYMBOL(pj_strcat) -PJ_EXPORT_SYMBOL(pj_strltrim) -PJ_EXPORT_SYMBOL(pj_strrtrim) -PJ_EXPORT_SYMBOL(pj_strtrim) -PJ_EXPORT_SYMBOL(pj_create_random_string) -PJ_EXPORT_SYMBOL(pj_strtoul) -PJ_EXPORT_SYMBOL(pj_utoa) -PJ_EXPORT_SYMBOL(pj_utoa_pad) - -/* - * stun.h - */ -PJ_EXPORT_SYMBOL(pj_stun_create_bind_req) -PJ_EXPORT_SYMBOL(pj_stun_parse_msg) -PJ_EXPORT_SYMBOL(pj_stun_msg_find_attr) -PJ_EXPORT_SYMBOL(pj_stun_get_mapped_addr) -PJ_EXPORT_SYMBOL(pj_stun_get_err_msg) - -/* - * timer.h - */ -PJ_EXPORT_SYMBOL(pj_timer_heap_mem_size) -PJ_EXPORT_SYMBOL(pj_timer_heap_create) -PJ_EXPORT_SYMBOL(pj_timer_entry_init) -PJ_EXPORT_SYMBOL(pj_timer_heap_schedule) -PJ_EXPORT_SYMBOL(pj_timer_heap_cancel) -PJ_EXPORT_SYMBOL(pj_timer_heap_count) -PJ_EXPORT_SYMBOL(pj_timer_heap_earliest_time) -PJ_EXPORT_SYMBOL(pj_timer_heap_poll) - -/* - * types.h - */ -PJ_EXPORT_SYMBOL(pj_time_val_normalize) - -/* - * xml.h - */ -PJ_EXPORT_SYMBOL(pj_xml_parse) -PJ_EXPORT_SYMBOL(pj_xml_print) -PJ_EXPORT_SYMBOL(pj_xml_add_node) -PJ_EXPORT_SYMBOL(pj_xml_add_attr) -PJ_EXPORT_SYMBOL(pj_xml_find_node) -PJ_EXPORT_SYMBOL(pj_xml_find_next_node) -PJ_EXPORT_SYMBOL(pj_xml_find_attr) -PJ_EXPORT_SYMBOL(pj_xml_find) - +/* $Header: /pjproject-0.3/pjlib/src/pj/symbols.c 3 10/29/05 11:51a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pj/symbols.c $ + * + * 3 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 10/05/05 4:43p Bennylp + * Created. + * + */ +#include + +/* + * addr_resolv.h + */ +PJ_EXPORT_SYMBOL(pj_gethostbyname) + +/* + * array.h + */ +PJ_EXPORT_SYMBOL(pj_array_insert) +PJ_EXPORT_SYMBOL(pj_array_erase) +PJ_EXPORT_SYMBOL(pj_array_find) + +/* + * config.h + */ +PJ_EXPORT_SYMBOL(pj_dump_config) + +/* + * errno.h + */ +PJ_EXPORT_SYMBOL(pj_get_os_error) +PJ_EXPORT_SYMBOL(pj_set_os_error) +PJ_EXPORT_SYMBOL(pj_get_netos_error) +PJ_EXPORT_SYMBOL(pj_set_netos_error) +PJ_EXPORT_SYMBOL(pj_strerror) + +/* + * except.h + */ +PJ_EXPORT_SYMBOL(pj_throw_exception_) +PJ_EXPORT_SYMBOL(pj_push_exception_handler_) +PJ_EXPORT_SYMBOL(pj_pop_exception_handler_) +PJ_EXPORT_SYMBOL(pj_setjmp) +PJ_EXPORT_SYMBOL(pj_longjmp) +PJ_EXPORT_SYMBOL(pj_exception_id_alloc) +PJ_EXPORT_SYMBOL(pj_exception_id_free) +PJ_EXPORT_SYMBOL(pj_exception_id_name) + + +/* + * fifobuf.h + */ +PJ_EXPORT_SYMBOL(pj_fifobuf_init) +PJ_EXPORT_SYMBOL(pj_fifobuf_max_size) +PJ_EXPORT_SYMBOL(pj_fifobuf_alloc) +PJ_EXPORT_SYMBOL(pj_fifobuf_unalloc) +PJ_EXPORT_SYMBOL(pj_fifobuf_free) + +/* + * guid.h + */ +PJ_EXPORT_SYMBOL(pj_generate_unique_string) +PJ_EXPORT_SYMBOL(pj_create_unique_string) + +/* + * hash.h + */ +PJ_EXPORT_SYMBOL(pj_hash_calc) +PJ_EXPORT_SYMBOL(pj_hash_create) +PJ_EXPORT_SYMBOL(pj_hash_get) +PJ_EXPORT_SYMBOL(pj_hash_set) +PJ_EXPORT_SYMBOL(pj_hash_count) +PJ_EXPORT_SYMBOL(pj_hash_first) +PJ_EXPORT_SYMBOL(pj_hash_next) +PJ_EXPORT_SYMBOL(pj_hash_this) + +/* + * ioqueue.h + */ +PJ_EXPORT_SYMBOL(pj_ioqueue_create) +PJ_EXPORT_SYMBOL(pj_ioqueue_destroy) +PJ_EXPORT_SYMBOL(pj_ioqueue_set_lock) +PJ_EXPORT_SYMBOL(pj_ioqueue_register_sock) +PJ_EXPORT_SYMBOL(pj_ioqueue_unregister) +PJ_EXPORT_SYMBOL(pj_ioqueue_get_user_data) +PJ_EXPORT_SYMBOL(pj_ioqueue_poll) +PJ_EXPORT_SYMBOL(pj_ioqueue_read) +PJ_EXPORT_SYMBOL(pj_ioqueue_recv) +PJ_EXPORT_SYMBOL(pj_ioqueue_recvfrom) +PJ_EXPORT_SYMBOL(pj_ioqueue_write) +PJ_EXPORT_SYMBOL(pj_ioqueue_send) +PJ_EXPORT_SYMBOL(pj_ioqueue_sendto) +#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 +PJ_EXPORT_SYMBOL(pj_ioqueue_accept) +PJ_EXPORT_SYMBOL(pj_ioqueue_connect) +#endif + +/* + * list.h + */ +PJ_EXPORT_SYMBOL(pj_list_insert_before) +PJ_EXPORT_SYMBOL(pj_list_insert_nodes_before) +PJ_EXPORT_SYMBOL(pj_list_insert_after) +PJ_EXPORT_SYMBOL(pj_list_insert_nodes_after) +PJ_EXPORT_SYMBOL(pj_list_merge_first) +PJ_EXPORT_SYMBOL(pj_list_merge_last) +PJ_EXPORT_SYMBOL(pj_list_erase) +PJ_EXPORT_SYMBOL(pj_list_find_node) +PJ_EXPORT_SYMBOL(pj_list_search) + + +/* + * log.h + */ +PJ_EXPORT_SYMBOL(pj_log_write) +#if PJ_LOG_MAX_LEVEL >= 1 +PJ_EXPORT_SYMBOL(pj_log_set_log_func) +PJ_EXPORT_SYMBOL(pj_log_get_log_func) +PJ_EXPORT_SYMBOL(pj_log_set_level) +PJ_EXPORT_SYMBOL(pj_log_get_level) +PJ_EXPORT_SYMBOL(pj_log_set_decor) +PJ_EXPORT_SYMBOL(pj_log_get_decor) +PJ_EXPORT_SYMBOL(pj_log_1) +#endif +#if PJ_LOG_MAX_LEVEL >= 2 +PJ_EXPORT_SYMBOL(pj_log_2) +#endif +#if PJ_LOG_MAX_LEVEL >= 3 +PJ_EXPORT_SYMBOL(pj_log_3) +#endif +#if PJ_LOG_MAX_LEVEL >= 4 +PJ_EXPORT_SYMBOL(pj_log_4) +#endif +#if PJ_LOG_MAX_LEVEL >= 5 +PJ_EXPORT_SYMBOL(pj_log_5) +#endif +#if PJ_LOG_MAX_LEVEL >= 6 +PJ_EXPORT_SYMBOL(pj_log_6) +#endif + +/* + * md5.h + */ +PJ_EXPORT_SYMBOL(md5_init) +PJ_EXPORT_SYMBOL(md5_append) +PJ_EXPORT_SYMBOL(md5_finish) + + +/* + * os.h + */ +PJ_EXPORT_SYMBOL(pj_init) +PJ_EXPORT_SYMBOL(pj_getpid) +PJ_EXPORT_SYMBOL(pj_thread_register) +PJ_EXPORT_SYMBOL(pj_thread_create) +PJ_EXPORT_SYMBOL(pj_thread_get_name) +PJ_EXPORT_SYMBOL(pj_thread_resume) +PJ_EXPORT_SYMBOL(pj_thread_this) +PJ_EXPORT_SYMBOL(pj_thread_join) +PJ_EXPORT_SYMBOL(pj_thread_destroy) +PJ_EXPORT_SYMBOL(pj_thread_sleep) +#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0 +PJ_EXPORT_SYMBOL(pj_thread_check_stack) +PJ_EXPORT_SYMBOL(pj_thread_get_stack_max_usage) +PJ_EXPORT_SYMBOL(pj_thread_get_stack_info) +#endif +PJ_EXPORT_SYMBOL(pj_atomic_create) +PJ_EXPORT_SYMBOL(pj_atomic_destroy) +PJ_EXPORT_SYMBOL(pj_atomic_set) +PJ_EXPORT_SYMBOL(pj_atomic_get) +PJ_EXPORT_SYMBOL(pj_atomic_inc) +PJ_EXPORT_SYMBOL(pj_atomic_dec) +PJ_EXPORT_SYMBOL(pj_thread_local_alloc) +PJ_EXPORT_SYMBOL(pj_thread_local_free) +PJ_EXPORT_SYMBOL(pj_thread_local_set) +PJ_EXPORT_SYMBOL(pj_thread_local_get) +PJ_EXPORT_SYMBOL(pj_enter_critical_section) +PJ_EXPORT_SYMBOL(pj_leave_critical_section) +PJ_EXPORT_SYMBOL(pj_mutex_create) +PJ_EXPORT_SYMBOL(pj_mutex_lock) +PJ_EXPORT_SYMBOL(pj_mutex_unlock) +PJ_EXPORT_SYMBOL(pj_mutex_trylock) +PJ_EXPORT_SYMBOL(pj_mutex_destroy) +#if defined(PJ_DEBUG) && PJ_DEBUG != 0 +PJ_EXPORT_SYMBOL(pj_mutex_is_locked) +#endif +#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 +PJ_EXPORT_SYMBOL(pj_sem_create) +PJ_EXPORT_SYMBOL(pj_sem_wait) +PJ_EXPORT_SYMBOL(pj_sem_trywait) +PJ_EXPORT_SYMBOL(pj_sem_post) +PJ_EXPORT_SYMBOL(pj_sem_destroy) +#endif +PJ_EXPORT_SYMBOL(pj_gettimeofday) +PJ_EXPORT_SYMBOL(pj_time_decode) +#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0 +PJ_EXPORT_SYMBOL(pj_get_timestamp) +PJ_EXPORT_SYMBOL(pj_get_timestamp_freq) +PJ_EXPORT_SYMBOL(pj_elapsed_time) +PJ_EXPORT_SYMBOL(pj_elapsed_usec) +PJ_EXPORT_SYMBOL(pj_elapsed_nanosec) +PJ_EXPORT_SYMBOL(pj_elapsed_cycle) +#endif + + +/* + * pool.h + */ +PJ_EXPORT_SYMBOL(pj_pool_create) +PJ_EXPORT_SYMBOL(pj_pool_release) +PJ_EXPORT_SYMBOL(pj_pool_getobjname) +PJ_EXPORT_SYMBOL(pj_pool_reset) +PJ_EXPORT_SYMBOL(pj_pool_get_capacity) +PJ_EXPORT_SYMBOL(pj_pool_get_used_size) +PJ_EXPORT_SYMBOL(pj_pool_alloc) +PJ_EXPORT_SYMBOL(pj_pool_calloc) +PJ_EXPORT_SYMBOL(pj_pool_factory_default_policy) +PJ_EXPORT_SYMBOL(pj_pool_create_int) +PJ_EXPORT_SYMBOL(pj_pool_init_int) +PJ_EXPORT_SYMBOL(pj_pool_destroy_int) +PJ_EXPORT_SYMBOL(pj_caching_pool_init) +PJ_EXPORT_SYMBOL(pj_caching_pool_destroy) + +/* + * rand.h + */ +PJ_EXPORT_SYMBOL(pj_rand) +PJ_EXPORT_SYMBOL(pj_srand) + +/* + * rbtree.h + */ +PJ_EXPORT_SYMBOL(pj_rbtree_init) +PJ_EXPORT_SYMBOL(pj_rbtree_first) +PJ_EXPORT_SYMBOL(pj_rbtree_last) +PJ_EXPORT_SYMBOL(pj_rbtree_next) +PJ_EXPORT_SYMBOL(pj_rbtree_prev) +PJ_EXPORT_SYMBOL(pj_rbtree_insert) +PJ_EXPORT_SYMBOL(pj_rbtree_find) +PJ_EXPORT_SYMBOL(pj_rbtree_erase) +PJ_EXPORT_SYMBOL(pj_rbtree_max_height) +PJ_EXPORT_SYMBOL(pj_rbtree_min_height) + +/* + * scanner.h + */ +PJ_EXPORT_SYMBOL(pj_cs_init) +PJ_EXPORT_SYMBOL(pj_cs_set) +PJ_EXPORT_SYMBOL(pj_cs_add_range) +PJ_EXPORT_SYMBOL(pj_cs_add_alpha) +PJ_EXPORT_SYMBOL(pj_cs_add_num) +PJ_EXPORT_SYMBOL(pj_cs_add_str) +PJ_EXPORT_SYMBOL(pj_cs_del_range) +PJ_EXPORT_SYMBOL(pj_cs_del_str) +PJ_EXPORT_SYMBOL(pj_cs_invert) +PJ_EXPORT_SYMBOL(pj_scan_init) +PJ_EXPORT_SYMBOL(pj_scan_fini) +PJ_EXPORT_SYMBOL(pj_scan_peek) +PJ_EXPORT_SYMBOL(pj_scan_peek_n) +PJ_EXPORT_SYMBOL(pj_scan_peek_until) +PJ_EXPORT_SYMBOL(pj_scan_get) +PJ_EXPORT_SYMBOL(pj_scan_get_quote) +PJ_EXPORT_SYMBOL(pj_scan_get_n) +PJ_EXPORT_SYMBOL(pj_scan_get_char) +PJ_EXPORT_SYMBOL(pj_scan_get_newline) +PJ_EXPORT_SYMBOL(pj_scan_get_until) +PJ_EXPORT_SYMBOL(pj_scan_get_until_ch) +PJ_EXPORT_SYMBOL(pj_scan_get_until_chr) +PJ_EXPORT_SYMBOL(pj_scan_advance_n) +PJ_EXPORT_SYMBOL(pj_scan_strcmp) +PJ_EXPORT_SYMBOL(pj_scan_stricmp) +PJ_EXPORT_SYMBOL(pj_scan_skip_whitespace) +PJ_EXPORT_SYMBOL(pj_scan_save_state) +PJ_EXPORT_SYMBOL(pj_scan_restore_state) + +/* + * sock.h + */ +PJ_EXPORT_SYMBOL(PJ_AF_UNIX) +PJ_EXPORT_SYMBOL(PJ_AF_INET) +PJ_EXPORT_SYMBOL(PJ_AF_INET6) +PJ_EXPORT_SYMBOL(PJ_AF_PACKET) +PJ_EXPORT_SYMBOL(PJ_AF_IRDA) +PJ_EXPORT_SYMBOL(PJ_SOCK_STREAM) +PJ_EXPORT_SYMBOL(PJ_SOCK_DGRAM) +PJ_EXPORT_SYMBOL(PJ_SOCK_RAW) +PJ_EXPORT_SYMBOL(PJ_SOCK_RDM) +PJ_EXPORT_SYMBOL(PJ_SOL_SOCKET) +PJ_EXPORT_SYMBOL(PJ_SOL_IP) +PJ_EXPORT_SYMBOL(PJ_SOL_TCP) +PJ_EXPORT_SYMBOL(PJ_SOL_UDP) +PJ_EXPORT_SYMBOL(PJ_SOL_IPV6) +PJ_EXPORT_SYMBOL(pj_ntohs) +PJ_EXPORT_SYMBOL(pj_htons) +PJ_EXPORT_SYMBOL(pj_ntohl) +PJ_EXPORT_SYMBOL(pj_htonl) +PJ_EXPORT_SYMBOL(pj_inet_ntoa) +PJ_EXPORT_SYMBOL(pj_inet_aton) +PJ_EXPORT_SYMBOL(pj_inet_addr) +PJ_EXPORT_SYMBOL(pj_sockaddr_in_set_str_addr) +PJ_EXPORT_SYMBOL(pj_sockaddr_in_init) +PJ_EXPORT_SYMBOL(pj_gethostname) +PJ_EXPORT_SYMBOL(pj_gethostaddr) +PJ_EXPORT_SYMBOL(pj_sock_socket) +PJ_EXPORT_SYMBOL(pj_sock_close) +PJ_EXPORT_SYMBOL(pj_sock_bind) +PJ_EXPORT_SYMBOL(pj_sock_bind_in) +#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 +PJ_EXPORT_SYMBOL(pj_sock_listen) +PJ_EXPORT_SYMBOL(pj_sock_accept) +PJ_EXPORT_SYMBOL(pj_sock_shutdown) +#endif +PJ_EXPORT_SYMBOL(pj_sock_connect) +PJ_EXPORT_SYMBOL(pj_sock_getpeername) +PJ_EXPORT_SYMBOL(pj_sock_getsockname) +PJ_EXPORT_SYMBOL(pj_sock_getsockopt) +PJ_EXPORT_SYMBOL(pj_sock_setsockopt) +PJ_EXPORT_SYMBOL(pj_sock_recv) +PJ_EXPORT_SYMBOL(pj_sock_recvfrom) +PJ_EXPORT_SYMBOL(pj_sock_send) +PJ_EXPORT_SYMBOL(pj_sock_sendto) + +/* + * sock_select.h + */ +PJ_EXPORT_SYMBOL(PJ_FD_ZERO) +PJ_EXPORT_SYMBOL(PJ_FD_SET) +PJ_EXPORT_SYMBOL(PJ_FD_CLR) +PJ_EXPORT_SYMBOL(PJ_FD_ISSET) +PJ_EXPORT_SYMBOL(pj_sock_select) + +/* + * string.h + */ +PJ_EXPORT_SYMBOL(pj_str) +PJ_EXPORT_SYMBOL(pj_strassign) +PJ_EXPORT_SYMBOL(pj_strcpy) +PJ_EXPORT_SYMBOL(pj_strcpy2) +PJ_EXPORT_SYMBOL(pj_strdup) +PJ_EXPORT_SYMBOL(pj_strdup_with_null) +PJ_EXPORT_SYMBOL(pj_strdup2) +PJ_EXPORT_SYMBOL(pj_strdup3) +PJ_EXPORT_SYMBOL(pj_strcmp) +PJ_EXPORT_SYMBOL(pj_strcmp2) +PJ_EXPORT_SYMBOL(pj_strncmp) +PJ_EXPORT_SYMBOL(pj_strncmp2) +PJ_EXPORT_SYMBOL(pj_stricmp) +PJ_EXPORT_SYMBOL(pj_stricmp2) +PJ_EXPORT_SYMBOL(pj_strnicmp) +PJ_EXPORT_SYMBOL(pj_strnicmp2) +PJ_EXPORT_SYMBOL(pj_strcat) +PJ_EXPORT_SYMBOL(pj_strltrim) +PJ_EXPORT_SYMBOL(pj_strrtrim) +PJ_EXPORT_SYMBOL(pj_strtrim) +PJ_EXPORT_SYMBOL(pj_create_random_string) +PJ_EXPORT_SYMBOL(pj_strtoul) +PJ_EXPORT_SYMBOL(pj_utoa) +PJ_EXPORT_SYMBOL(pj_utoa_pad) + +/* + * stun.h + */ +PJ_EXPORT_SYMBOL(pj_stun_create_bind_req) +PJ_EXPORT_SYMBOL(pj_stun_parse_msg) +PJ_EXPORT_SYMBOL(pj_stun_msg_find_attr) +PJ_EXPORT_SYMBOL(pj_stun_get_mapped_addr) +PJ_EXPORT_SYMBOL(pj_stun_get_err_msg) + +/* + * timer.h + */ +PJ_EXPORT_SYMBOL(pj_timer_heap_mem_size) +PJ_EXPORT_SYMBOL(pj_timer_heap_create) +PJ_EXPORT_SYMBOL(pj_timer_entry_init) +PJ_EXPORT_SYMBOL(pj_timer_heap_schedule) +PJ_EXPORT_SYMBOL(pj_timer_heap_cancel) +PJ_EXPORT_SYMBOL(pj_timer_heap_count) +PJ_EXPORT_SYMBOL(pj_timer_heap_earliest_time) +PJ_EXPORT_SYMBOL(pj_timer_heap_poll) + +/* + * types.h + */ +PJ_EXPORT_SYMBOL(pj_time_val_normalize) + +/* + * xml.h + */ +PJ_EXPORT_SYMBOL(pj_xml_parse) +PJ_EXPORT_SYMBOL(pj_xml_print) +PJ_EXPORT_SYMBOL(pj_xml_add_node) +PJ_EXPORT_SYMBOL(pj_xml_add_attr) +PJ_EXPORT_SYMBOL(pj_xml_find_node) +PJ_EXPORT_SYMBOL(pj_xml_find_next_node) +PJ_EXPORT_SYMBOL(pj_xml_find_attr) +PJ_EXPORT_SYMBOL(pj_xml_find) + diff --git a/pjlib/src/pj/timer.c b/pjlib/src/pj/timer.c index 5cd09ea4..2bf9842a 100644 --- a/pjlib/src/pj/timer.c +++ b/pjlib/src/pj/timer.c @@ -1,504 +1,504 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/timer.c 8 10/14/05 12:26a Bennylp $ */ -/* (C)1993-2003 Douglas C. Schmidt - * - * This file is originaly from ACE library by Doug Schmidt - * ACE(TM), TAO(TM) and CIAO(TM) are copyrighted by Douglas C. Schmidt and his research - * group at Washington University, University of California, Irvine, and Vanderbilt - * University Copyright (c) 1993-2003, all rights reserved. - */ -/* $Log: /pjproject-0.3/pjlib/src/pj/timer.c $ - * - * 8 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 7 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 6 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include -#include -#include -#include - -#define HEAP_PARENT(X) (X == 0 ? 0 : (((X) - 1) / 2)) -#define HEAP_LEFT(X) (((X)+(X))+1) - - -/** - * The implementation of timer heap. - */ -struct pj_timer_heap_t -{ - /** Pool from which the timer heap resize will get the storage from */ - pj_pool_t *pool; - - /** Maximum size of the heap. */ - pj_size_t max_size; - - /** Current size of the heap. */ - pj_size_t cur_size; - - /** Mutex for synchronization, or NULL */ - pj_mutex_t *mutex; - - /** - * Current contents of the Heap, which is organized as a "heap" of - * pj_timer_entry *'s. In this context, a heap is a "partially - * ordered, almost complete" binary tree, which is stored in an - * array. - */ - pj_timer_entry **heap; - - /** - * An array of "pointers" that allows each pj_timer_entry in the - * to be located in O(1) time. Basically, - * contains the slot in the array where an pj_timer_entry - * with timer id resides. Thus, the timer id passed back from - * is really an slot into the array. The - * array serves two purposes: negative values are - * treated as "pointers" for the , whereas positive - * values are treated as "pointers" into the array. - */ - pj_timer_id_t *timer_ids; - - /** - * "Pointer" to the first element in the freelist contained within - * the array, which is organized as a stack. - */ - pj_timer_id_t timer_ids_freelist; - - /** Callback to be called when a timer expires. */ - pj_timer_heap_callback *callback; - -}; - - - -PJ_INLINE(void) lock_timer_heap( pj_timer_heap_t *ht ) -{ - if (ht->mutex) { - pj_mutex_lock(ht->mutex); - } -} - -PJ_INLINE(void) unlock_timer_heap( pj_timer_heap_t *ht ) -{ - if (ht->mutex) { - pj_mutex_unlock(ht->mutex); - } -} - - -static void copy_node( pj_timer_heap_t *ht, int slot, pj_timer_entry *moved_node ) -{ - PJ_CHECK_STACK(); - - // Insert into its new location in the heap. - ht->heap[slot] = moved_node; - - // Update the corresponding slot in the parallel array. - ht->timer_ids[moved_node->_timer_id] = slot; -} - -static pj_timer_id_t pop_freelist( pj_timer_heap_t *ht ) -{ - // We need to truncate this to for backwards compatibility. - pj_timer_id_t new_id = ht->timer_ids_freelist; - - PJ_CHECK_STACK(); - - // The freelist values in the are negative, so we need - // to negate them to get the next freelist "pointer." - ht->timer_ids_freelist = - -ht->timer_ids[ht->timer_ids_freelist]; - - return new_id; - -} - -static void push_freelist (pj_timer_heap_t *ht, pj_timer_id_t old_id) -{ - PJ_CHECK_STACK(); - - // The freelist values in the are negative, so we need - // to negate them to get the next freelist "pointer." - ht->timer_ids[old_id] = -ht->timer_ids_freelist; - ht->timer_ids_freelist = old_id; -} - - -static void reheap_down(pj_timer_heap_t *ht, pj_timer_entry *moved_node, - size_t slot, size_t child) -{ - PJ_CHECK_STACK(); - - // Restore the heap property after a deletion. - - while (child < ht->cur_size) - { - // Choose the smaller of the two children. - if (child + 1 < ht->cur_size - && PJ_TIME_VAL_LT(ht->heap[child + 1]->_timer_value, ht->heap[child]->_timer_value)) - child++; - - // Perform a if the child has a larger timeout value than - // the . - if (PJ_TIME_VAL_LT(ht->heap[child]->_timer_value, moved_node->_timer_value)) - { - copy_node( ht, slot, ht->heap[child]); - slot = child; - child = HEAP_LEFT(child); - } - else - // We've found our location in the heap. - break; - } - - copy_node( ht, slot, moved_node); -} - -static void reheap_up( pj_timer_heap_t *ht, pj_timer_entry *moved_node, - size_t slot, size_t parent) -{ - // Restore the heap property after an insertion. - - while (slot > 0) - { - // If the parent node is greater than the we need - // to copy it down. - if (PJ_TIME_VAL_LT(moved_node->_timer_value, ht->heap[parent]->_timer_value)) - { - copy_node(ht, slot, ht->heap[parent]); - slot = parent; - parent = HEAP_PARENT(slot); - } - else - break; - } - - // Insert the new node into its proper resting place in the heap and - // update the corresponding slot in the parallel array. - copy_node(ht, slot, moved_node); -} - - -static pj_timer_entry * remove_node( pj_timer_heap_t *ht, size_t slot) -{ - pj_timer_entry *removed_node = ht->heap[slot]; - - // Return this timer id to the freelist. - push_freelist( ht, removed_node->_timer_id ); - - // Decrement the size of the heap by one since we're removing the - // "slot"th node. - ht->cur_size--; - - // Set the ID - removed_node->_timer_id = -1; - - // Only try to reheapify if we're not deleting the last entry. - - if (slot < ht->cur_size) - { - int parent; - pj_timer_entry *moved_node = ht->heap[ht->cur_size]; - - // Move the end node to the location being removed and update - // the corresponding slot in the parallel array. - copy_node( ht, slot, moved_node); - - // If the time_value_> is great than or equal its - // parent it needs be moved down the heap. - parent = HEAP_PARENT (slot); - - if (PJ_TIME_VAL_GTE(moved_node->_timer_value, ht->heap[parent]->_timer_value)) - reheap_down( ht, moved_node, slot, HEAP_LEFT(slot)); - else - reheap_up( ht, moved_node, slot, parent); - } - - return removed_node; -} - -static void grow_heap(pj_timer_heap_t *ht) -{ - // All the containers will double in size from max_size_ - size_t new_size = ht->max_size * 2; - pj_timer_id_t *new_timer_ids; - pj_size_t i; - - // First grow the heap itself. - - pj_timer_entry **new_heap = 0; - - new_heap = pj_pool_alloc(ht->pool, sizeof(pj_timer_entry*) * new_size); - memcpy(new_heap, ht->heap, ht->max_size * sizeof(pj_timer_entry*)); - //delete [] this->heap_; - ht->heap = new_heap; - - // Grow the array of timer ids. - - new_timer_ids = 0; - new_timer_ids = pj_pool_alloc(ht->pool, new_size * sizeof(pj_timer_id_t)); - - memcpy( new_timer_ids, ht->timer_ids, ht->max_size * sizeof(pj_timer_id_t)); - - //delete [] timer_ids_; - ht->timer_ids = new_timer_ids; - - // And add the new elements to the end of the "freelist". - for (i = ht->max_size; i < new_size; i++) - ht->timer_ids[i] = -((pj_timer_id_t) (i + 1)); - - ht->max_size = new_size; -} - -static void insert_node(pj_timer_heap_t *ht, pj_timer_entry *new_node) -{ - if (ht->cur_size + 2 >= ht->max_size) - grow_heap(ht); - - reheap_up( ht, new_node, ht->cur_size, HEAP_PARENT(ht->cur_size)); - ht->cur_size++; -} - - -static pj_status_t schedule_entry( pj_timer_heap_t *ht, - pj_timer_entry *entry, - const pj_time_val *future_time ) -{ - if (ht->cur_size < ht->max_size) - { - // Obtain the next unique sequence number. - // Set the entry - entry->_timer_id = pop_freelist(ht); - entry->_timer_value = *future_time; - insert_node( ht, entry); - return 0; - } - else - return -1; -} - - -static int cancel( pj_timer_heap_t *ht, - pj_timer_entry *entry, - int dont_call) -{ - long timer_node_slot; - - PJ_CHECK_STACK(); - - // Check to see if the timer_id is out of range - if (entry->_timer_id < 0 || (pj_size_t)entry->_timer_id > ht->max_size) - return 0; - - timer_node_slot = ht->timer_ids[entry->_timer_id]; - - if (timer_node_slot < 0) // Check to see if timer_id is still valid. - return 0; - - if (entry != ht->heap[timer_node_slot]) - { - pj_assert(entry == ht->heap[timer_node_slot]); - return 0; - } - else - { - remove_node( ht, timer_node_slot); - - if (dont_call == 0) - // Call the close hook. - (*ht->callback)(ht, entry); - return 1; - } -} - - -/* - * Calculate memory size required to create a timer heap. - */ -PJ_DEF(pj_size_t) pj_timer_heap_mem_size(pj_size_t count) -{ - return /* size of the timer heap itself: */ - sizeof(pj_timer_heap_t) + - /* size of each entry: */ - (count+2) * (sizeof(pj_timer_entry*)+sizeof(pj_timer_id_t)) + - /* mutex, pool etc: */ - 132; -} - -/* - * Create a new timer heap. - */ -PJ_DEF(pj_status_t) pj_timer_heap_create( pj_pool_t *pool, - pj_size_t size, - unsigned flag, - pj_timer_heap_t **p_heap) -{ - pj_timer_heap_t *ht; - pj_size_t i; - - PJ_ASSERT_RETURN(pool && p_heap, PJ_EINVAL); - - *p_heap = NULL; - - /* Magic? */ - size += 2; - - /* Allocate timer heap data structure from the pool */ - ht = pj_pool_alloc(pool, sizeof(pj_timer_heap_t)); - if (!ht) - return PJ_ENOMEM; - - /* Initialize timer heap sizes */ - ht->max_size = size; - ht->cur_size = 0; - ht->timer_ids_freelist = 1; - ht->pool = pool; - - /* Mutex. */ - if (flag & PJ_TIMER_HEAP_NO_SYNCHRONIZE) { - ht->mutex = NULL; - } else { - pj_status_t rc; - - /* Mutex must be the recursive types. - * See commented code inside pj_timer_heap_poll() - */ - rc = pj_mutex_create(pool, "tmhp%p", PJ_MUTEX_RECURSE, &ht->mutex); - if (rc != PJ_SUCCESS) - return rc; - } - - // Create the heap array. - ht->heap = pj_pool_alloc(pool, sizeof(pj_timer_entry*) * size); - if (!ht->heap) - return PJ_ENOMEM; - - // Create the parallel - ht->timer_ids = pj_pool_alloc( pool, sizeof(pj_timer_id_t) * size); - if (!ht->timer_ids) - return PJ_ENOMEM; - - // Initialize the "freelist," which uses negative values to - // distinguish freelist elements from "pointers" into the - // array. - for (i=0; itimer_ids[i] = -((pj_timer_id_t) (i + 1)); - - *p_heap = ht; - return PJ_SUCCESS; -} - -PJ_DEF(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry, - int id, - void *user_data, - pj_timer_heap_callback *cb ) -{ - pj_assert(entry && cb); - - entry->id = id; - entry->user_data = user_data; - entry->cb = cb; - - return entry; -} - -PJ_DEF(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht, - pj_timer_entry *entry, - const pj_time_val *delay) -{ - pj_status_t status; - pj_time_val expires; - - PJ_ASSERT_RETURN(ht && entry && delay, PJ_EINVAL); - - pj_gettimeofday(&expires); - PJ_TIME_VAL_ADD(expires, *delay); - - lock_timer_heap(ht); - status = schedule_entry(ht, entry, &expires); - unlock_timer_heap(ht); - - return status; -} - -PJ_DEF(int) pj_timer_heap_cancel( pj_timer_heap_t *ht, - pj_timer_entry *entry) -{ - int count; - - PJ_ASSERT_RETURN(ht && entry, PJ_EINVAL); - - lock_timer_heap(ht); - count = cancel(ht, entry, 1); - unlock_timer_heap(ht); - - return count; -} - -PJ_DEF(int) pj_timer_heap_poll( pj_timer_heap_t *ht, pj_time_val *next_delay ) -{ - pj_time_val now; - int count; - - PJ_ASSERT_RETURN(ht, -1); - - if (!ht->cur_size && next_delay) { - next_delay->sec = next_delay->msec = PJ_MAXINT32; - return 0; - } - - count = 0; - pj_gettimeofday(&now); - - lock_timer_heap(ht); - while ( ht->cur_size && - PJ_TIME_VAL_LTE(ht->heap[0]->_timer_value, now) ) - { - pj_timer_entry *node = remove_node(ht, 0); - ++count; - - //Better not to temporarily release mutex to save some syscalls. - //But then make sure the mutex must be the recursive types (PJ_MUTEX_RECURSE)! - //unlock_timer_heap(ht); - (*node->cb)(ht, node); - //lock_timer_heap(ht); - } - if (ht->cur_size && next_delay) { - *next_delay = ht->heap[0]->_timer_value; - PJ_TIME_VAL_SUB(*next_delay, now); - } else if (next_delay) { - next_delay->sec = next_delay->msec = PJ_MAXINT32; - } - unlock_timer_heap(ht); - - return count; -} - -PJ_DEF(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht ) -{ - return ht->cur_size; -} - -PJ_DEF(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t * ht, - pj_time_val *timeval) -{ - pj_assert(ht->cur_size != 0); - if (ht->cur_size == 0) - return PJ_ENOTFOUND; - - lock_timer_heap(ht); - *timeval = ht->heap[0]->_timer_value; - unlock_timer_heap(ht); - - return PJ_SUCCESS; -} - +/* $Header: /pjproject-0.3/pjlib/src/pj/timer.c 8 10/14/05 12:26a Bennylp $ */ +/* (C)1993-2003 Douglas C. Schmidt + * + * This file is originaly from ACE library by Doug Schmidt + * ACE(TM), TAO(TM) and CIAO(TM) are copyrighted by Douglas C. Schmidt and his research + * group at Washington University, University of California, Irvine, and Vanderbilt + * University Copyright (c) 1993-2003, all rights reserved. + */ +/* $Log: /pjproject-0.3/pjlib/src/pj/timer.c $ + * + * 8 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 7 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 6 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include +#include +#include +#include +#include + +#define HEAP_PARENT(X) (X == 0 ? 0 : (((X) - 1) / 2)) +#define HEAP_LEFT(X) (((X)+(X))+1) + + +/** + * The implementation of timer heap. + */ +struct pj_timer_heap_t +{ + /** Pool from which the timer heap resize will get the storage from */ + pj_pool_t *pool; + + /** Maximum size of the heap. */ + pj_size_t max_size; + + /** Current size of the heap. */ + pj_size_t cur_size; + + /** Mutex for synchronization, or NULL */ + pj_mutex_t *mutex; + + /** + * Current contents of the Heap, which is organized as a "heap" of + * pj_timer_entry *'s. In this context, a heap is a "partially + * ordered, almost complete" binary tree, which is stored in an + * array. + */ + pj_timer_entry **heap; + + /** + * An array of "pointers" that allows each pj_timer_entry in the + * to be located in O(1) time. Basically, + * contains the slot in the array where an pj_timer_entry + * with timer id resides. Thus, the timer id passed back from + * is really an slot into the array. The + * array serves two purposes: negative values are + * treated as "pointers" for the , whereas positive + * values are treated as "pointers" into the array. + */ + pj_timer_id_t *timer_ids; + + /** + * "Pointer" to the first element in the freelist contained within + * the array, which is organized as a stack. + */ + pj_timer_id_t timer_ids_freelist; + + /** Callback to be called when a timer expires. */ + pj_timer_heap_callback *callback; + +}; + + + +PJ_INLINE(void) lock_timer_heap( pj_timer_heap_t *ht ) +{ + if (ht->mutex) { + pj_mutex_lock(ht->mutex); + } +} + +PJ_INLINE(void) unlock_timer_heap( pj_timer_heap_t *ht ) +{ + if (ht->mutex) { + pj_mutex_unlock(ht->mutex); + } +} + + +static void copy_node( pj_timer_heap_t *ht, int slot, pj_timer_entry *moved_node ) +{ + PJ_CHECK_STACK(); + + // Insert into its new location in the heap. + ht->heap[slot] = moved_node; + + // Update the corresponding slot in the parallel array. + ht->timer_ids[moved_node->_timer_id] = slot; +} + +static pj_timer_id_t pop_freelist( pj_timer_heap_t *ht ) +{ + // We need to truncate this to for backwards compatibility. + pj_timer_id_t new_id = ht->timer_ids_freelist; + + PJ_CHECK_STACK(); + + // The freelist values in the are negative, so we need + // to negate them to get the next freelist "pointer." + ht->timer_ids_freelist = + -ht->timer_ids[ht->timer_ids_freelist]; + + return new_id; + +} + +static void push_freelist (pj_timer_heap_t *ht, pj_timer_id_t old_id) +{ + PJ_CHECK_STACK(); + + // The freelist values in the are negative, so we need + // to negate them to get the next freelist "pointer." + ht->timer_ids[old_id] = -ht->timer_ids_freelist; + ht->timer_ids_freelist = old_id; +} + + +static void reheap_down(pj_timer_heap_t *ht, pj_timer_entry *moved_node, + size_t slot, size_t child) +{ + PJ_CHECK_STACK(); + + // Restore the heap property after a deletion. + + while (child < ht->cur_size) + { + // Choose the smaller of the two children. + if (child + 1 < ht->cur_size + && PJ_TIME_VAL_LT(ht->heap[child + 1]->_timer_value, ht->heap[child]->_timer_value)) + child++; + + // Perform a if the child has a larger timeout value than + // the . + if (PJ_TIME_VAL_LT(ht->heap[child]->_timer_value, moved_node->_timer_value)) + { + copy_node( ht, slot, ht->heap[child]); + slot = child; + child = HEAP_LEFT(child); + } + else + // We've found our location in the heap. + break; + } + + copy_node( ht, slot, moved_node); +} + +static void reheap_up( pj_timer_heap_t *ht, pj_timer_entry *moved_node, + size_t slot, size_t parent) +{ + // Restore the heap property after an insertion. + + while (slot > 0) + { + // If the parent node is greater than the we need + // to copy it down. + if (PJ_TIME_VAL_LT(moved_node->_timer_value, ht->heap[parent]->_timer_value)) + { + copy_node(ht, slot, ht->heap[parent]); + slot = parent; + parent = HEAP_PARENT(slot); + } + else + break; + } + + // Insert the new node into its proper resting place in the heap and + // update the corresponding slot in the parallel array. + copy_node(ht, slot, moved_node); +} + + +static pj_timer_entry * remove_node( pj_timer_heap_t *ht, size_t slot) +{ + pj_timer_entry *removed_node = ht->heap[slot]; + + // Return this timer id to the freelist. + push_freelist( ht, removed_node->_timer_id ); + + // Decrement the size of the heap by one since we're removing the + // "slot"th node. + ht->cur_size--; + + // Set the ID + removed_node->_timer_id = -1; + + // Only try to reheapify if we're not deleting the last entry. + + if (slot < ht->cur_size) + { + int parent; + pj_timer_entry *moved_node = ht->heap[ht->cur_size]; + + // Move the end node to the location being removed and update + // the corresponding slot in the parallel array. + copy_node( ht, slot, moved_node); + + // If the time_value_> is great than or equal its + // parent it needs be moved down the heap. + parent = HEAP_PARENT (slot); + + if (PJ_TIME_VAL_GTE(moved_node->_timer_value, ht->heap[parent]->_timer_value)) + reheap_down( ht, moved_node, slot, HEAP_LEFT(slot)); + else + reheap_up( ht, moved_node, slot, parent); + } + + return removed_node; +} + +static void grow_heap(pj_timer_heap_t *ht) +{ + // All the containers will double in size from max_size_ + size_t new_size = ht->max_size * 2; + pj_timer_id_t *new_timer_ids; + pj_size_t i; + + // First grow the heap itself. + + pj_timer_entry **new_heap = 0; + + new_heap = pj_pool_alloc(ht->pool, sizeof(pj_timer_entry*) * new_size); + memcpy(new_heap, ht->heap, ht->max_size * sizeof(pj_timer_entry*)); + //delete [] this->heap_; + ht->heap = new_heap; + + // Grow the array of timer ids. + + new_timer_ids = 0; + new_timer_ids = pj_pool_alloc(ht->pool, new_size * sizeof(pj_timer_id_t)); + + memcpy( new_timer_ids, ht->timer_ids, ht->max_size * sizeof(pj_timer_id_t)); + + //delete [] timer_ids_; + ht->timer_ids = new_timer_ids; + + // And add the new elements to the end of the "freelist". + for (i = ht->max_size; i < new_size; i++) + ht->timer_ids[i] = -((pj_timer_id_t) (i + 1)); + + ht->max_size = new_size; +} + +static void insert_node(pj_timer_heap_t *ht, pj_timer_entry *new_node) +{ + if (ht->cur_size + 2 >= ht->max_size) + grow_heap(ht); + + reheap_up( ht, new_node, ht->cur_size, HEAP_PARENT(ht->cur_size)); + ht->cur_size++; +} + + +static pj_status_t schedule_entry( pj_timer_heap_t *ht, + pj_timer_entry *entry, + const pj_time_val *future_time ) +{ + if (ht->cur_size < ht->max_size) + { + // Obtain the next unique sequence number. + // Set the entry + entry->_timer_id = pop_freelist(ht); + entry->_timer_value = *future_time; + insert_node( ht, entry); + return 0; + } + else + return -1; +} + + +static int cancel( pj_timer_heap_t *ht, + pj_timer_entry *entry, + int dont_call) +{ + long timer_node_slot; + + PJ_CHECK_STACK(); + + // Check to see if the timer_id is out of range + if (entry->_timer_id < 0 || (pj_size_t)entry->_timer_id > ht->max_size) + return 0; + + timer_node_slot = ht->timer_ids[entry->_timer_id]; + + if (timer_node_slot < 0) // Check to see if timer_id is still valid. + return 0; + + if (entry != ht->heap[timer_node_slot]) + { + pj_assert(entry == ht->heap[timer_node_slot]); + return 0; + } + else + { + remove_node( ht, timer_node_slot); + + if (dont_call == 0) + // Call the close hook. + (*ht->callback)(ht, entry); + return 1; + } +} + + +/* + * Calculate memory size required to create a timer heap. + */ +PJ_DEF(pj_size_t) pj_timer_heap_mem_size(pj_size_t count) +{ + return /* size of the timer heap itself: */ + sizeof(pj_timer_heap_t) + + /* size of each entry: */ + (count+2) * (sizeof(pj_timer_entry*)+sizeof(pj_timer_id_t)) + + /* mutex, pool etc: */ + 132; +} + +/* + * Create a new timer heap. + */ +PJ_DEF(pj_status_t) pj_timer_heap_create( pj_pool_t *pool, + pj_size_t size, + unsigned flag, + pj_timer_heap_t **p_heap) +{ + pj_timer_heap_t *ht; + pj_size_t i; + + PJ_ASSERT_RETURN(pool && p_heap, PJ_EINVAL); + + *p_heap = NULL; + + /* Magic? */ + size += 2; + + /* Allocate timer heap data structure from the pool */ + ht = pj_pool_alloc(pool, sizeof(pj_timer_heap_t)); + if (!ht) + return PJ_ENOMEM; + + /* Initialize timer heap sizes */ + ht->max_size = size; + ht->cur_size = 0; + ht->timer_ids_freelist = 1; + ht->pool = pool; + + /* Mutex. */ + if (flag & PJ_TIMER_HEAP_NO_SYNCHRONIZE) { + ht->mutex = NULL; + } else { + pj_status_t rc; + + /* Mutex must be the recursive types. + * See commented code inside pj_timer_heap_poll() + */ + rc = pj_mutex_create(pool, "tmhp%p", PJ_MUTEX_RECURSE, &ht->mutex); + if (rc != PJ_SUCCESS) + return rc; + } + + // Create the heap array. + ht->heap = pj_pool_alloc(pool, sizeof(pj_timer_entry*) * size); + if (!ht->heap) + return PJ_ENOMEM; + + // Create the parallel + ht->timer_ids = pj_pool_alloc( pool, sizeof(pj_timer_id_t) * size); + if (!ht->timer_ids) + return PJ_ENOMEM; + + // Initialize the "freelist," which uses negative values to + // distinguish freelist elements from "pointers" into the + // array. + for (i=0; itimer_ids[i] = -((pj_timer_id_t) (i + 1)); + + *p_heap = ht; + return PJ_SUCCESS; +} + +PJ_DEF(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry, + int id, + void *user_data, + pj_timer_heap_callback *cb ) +{ + pj_assert(entry && cb); + + entry->id = id; + entry->user_data = user_data; + entry->cb = cb; + + return entry; +} + +PJ_DEF(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht, + pj_timer_entry *entry, + const pj_time_val *delay) +{ + pj_status_t status; + pj_time_val expires; + + PJ_ASSERT_RETURN(ht && entry && delay, PJ_EINVAL); + + pj_gettimeofday(&expires); + PJ_TIME_VAL_ADD(expires, *delay); + + lock_timer_heap(ht); + status = schedule_entry(ht, entry, &expires); + unlock_timer_heap(ht); + + return status; +} + +PJ_DEF(int) pj_timer_heap_cancel( pj_timer_heap_t *ht, + pj_timer_entry *entry) +{ + int count; + + PJ_ASSERT_RETURN(ht && entry, PJ_EINVAL); + + lock_timer_heap(ht); + count = cancel(ht, entry, 1); + unlock_timer_heap(ht); + + return count; +} + +PJ_DEF(int) pj_timer_heap_poll( pj_timer_heap_t *ht, pj_time_val *next_delay ) +{ + pj_time_val now; + int count; + + PJ_ASSERT_RETURN(ht, -1); + + if (!ht->cur_size && next_delay) { + next_delay->sec = next_delay->msec = PJ_MAXINT32; + return 0; + } + + count = 0; + pj_gettimeofday(&now); + + lock_timer_heap(ht); + while ( ht->cur_size && + PJ_TIME_VAL_LTE(ht->heap[0]->_timer_value, now) ) + { + pj_timer_entry *node = remove_node(ht, 0); + ++count; + + //Better not to temporarily release mutex to save some syscalls. + //But then make sure the mutex must be the recursive types (PJ_MUTEX_RECURSE)! + //unlock_timer_heap(ht); + (*node->cb)(ht, node); + //lock_timer_heap(ht); + } + if (ht->cur_size && next_delay) { + *next_delay = ht->heap[0]->_timer_value; + PJ_TIME_VAL_SUB(*next_delay, now); + } else if (next_delay) { + next_delay->sec = next_delay->msec = PJ_MAXINT32; + } + unlock_timer_heap(ht); + + return count; +} + +PJ_DEF(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht ) +{ + return ht->cur_size; +} + +PJ_DEF(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t * ht, + pj_time_val *timeval) +{ + pj_assert(ht->cur_size != 0); + if (ht->cur_size == 0) + return PJ_ENOTFOUND; + + lock_timer_heap(ht); + *timeval = ht->heap[0]->_timer_value; + unlock_timer_heap(ht); + + return PJ_SUCCESS; +} + diff --git a/pjlib/src/pj/types.c b/pjlib/src/pj/types.c index ee1a8588..4a725238 100644 --- a/pjlib/src/pj/types.c +++ b/pjlib/src/pj/types.c @@ -1,36 +1,36 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/types.c 4 9/17/05 10:37a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/types.c $ - * - * 4 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include - -void pj_time_val_normalize(pj_time_val *t) -{ - PJ_CHECK_STACK(); - - if (t->msec >= 1000) { - do { - t->sec++; - t->msec -= 1000; - } while (t->msec >= 1000); - } - else if (t->msec <= -1000) { - do { - t->sec--; - t->msec += 1000; - } while (t->msec <= -1000); - } - - if (t->sec >= 1 && t->msec < 0) { - t->sec--; - t->msec += 1000; - - } else if (t->sec < 0 && t->msec > 0) { - t->sec++; - t->msec -= 1000; - } -} +/* $Header: /pjproject-0.3/pjlib/src/pj/types.c 4 9/17/05 10:37a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/types.c $ + * + * 4 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include + +void pj_time_val_normalize(pj_time_val *t) +{ + PJ_CHECK_STACK(); + + if (t->msec >= 1000) { + do { + t->sec++; + t->msec -= 1000; + } while (t->msec >= 1000); + } + else if (t->msec <= -1000) { + do { + t->sec--; + t->msec += 1000; + } while (t->msec <= -1000); + } + + if (t->sec >= 1 && t->msec < 0) { + t->sec--; + t->msec += 1000; + + } else if (t->sec < 0 && t->msec > 0) { + t->sec++; + t->msec -= 1000; + } +} diff --git a/pjlib/src/pj/xml.c b/pjlib/src/pj/xml.c index ff3684a8..8dccedec 100644 --- a/pjlib/src/pj/xml.c +++ b/pjlib/src/pj/xml.c @@ -1,392 +1,392 @@ -/* $Header: /pjproject-0.3/pjlib/src/pj/xml.c 9 10/14/05 12:26a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pj/xml.c $ - * - * 9 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 8 9/21/05 1:39p Bennylp - * Periodic checkin for backup. - * - * 7 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - */ -#include -#include -#include -#include -#include -#include -#include - -#define EX_SYNTAX_ERROR 12 -#define THIS_FILE "xml.c" - -static void on_syntax_error(struct pj_scanner *scanner) -{ - PJ_UNUSED_ARG(scanner); - PJ_THROW(EX_SYNTAX_ERROR); -} - -static pj_xml_node *alloc_node( pj_pool_t *pool ) -{ - pj_xml_node *node; - - node = pj_pool_calloc(pool, 1, sizeof(pj_xml_node)); - pj_list_init( &node->attr_head ); - pj_list_init( &node->node_head ); - - return node; -} - -static pj_xml_attr *alloc_attr( pj_pool_t *pool ) -{ - return pj_pool_calloc(pool, 1, sizeof(pj_xml_attr)); -} - -/* This is a recursive function! */ -static pj_xml_node *xml_parse_node( pj_pool_t *pool, pj_scanner *scanner) -{ - pj_xml_node *node; - pj_str_t end_name; - - PJ_CHECK_STACK(); - - if (*scanner->curptr != '<') - on_syntax_error(scanner); - - /* Handle Processing Instructino (PI) construct (i.e. "curptr == '<' && *(scanner->curptr+1) == '?') { - pj_scan_advance_n(scanner, 2, PJ_FALSE); - for (;;) { - pj_str_t dummy; - pj_scan_get_until_ch(scanner, '?', &dummy); - if (*scanner->curptr=='?' && *(scanner->curptr+1)=='>') { - pj_scan_advance_n(scanner, 2, PJ_TRUE); - break; - } else { - pj_scan_advance_n(scanner, 1, PJ_FALSE); - } - } - return xml_parse_node(pool, scanner); - } - - /* Handle comments construct (i.e. "", 3) == 0) { - pj_scan_advance_n(scanner, 3, PJ_TRUE); - break; - } else { - pj_scan_advance_n(scanner, 1, PJ_FALSE); - } - } - return xml_parse_node(pool, scanner); - } - - /* Alloc node. */ - node = alloc_node(pool); - - /* Get '<' */ - pj_scan_get_char(scanner); - - /* Get node name. */ - pj_scan_get_until_chr( scanner, " />\t", &node->name); - - /* Get attributes. */ - while (*scanner->curptr != '>' && *scanner->curptr != '/') { - pj_xml_attr *attr = alloc_attr(pool); - - pj_scan_get_until_chr( scanner, "=> \t", &attr->name); - if (*scanner->curptr == '=') { - pj_scan_get_char( scanner ); - pj_scan_get_quote(scanner, '"', '"', &attr->value); - /* remove quote characters */ - ++attr->value.ptr; - attr->value.slen -= 2; - } - - pj_list_insert_before( &node->attr_head, attr ); - } - - if (*scanner->curptr == '/') { - pj_scan_get_char(scanner); - if (pj_scan_get_char(scanner) != '>') - on_syntax_error(scanner); - return node; - } - - /* Enclosing bracket. */ - if (pj_scan_get_char(scanner) != '>') - on_syntax_error(scanner); - - /* Sub nodes. */ - while (*scanner->curptr == '<' && *(scanner->curptr+1) != '/') { - pj_xml_node *sub_node = xml_parse_node(pool, scanner); - pj_list_insert_before( &node->node_head, sub_node ); - } - - /* Content. */ - if (!pj_scan_is_eof(scanner) && *scanner->curptr != '<') { - pj_scan_get_until_ch(scanner, '<', &node->content); - } - - /* Enclosing node. */ - if (pj_scan_get_char(scanner) != '<' || pj_scan_get_char(scanner) != '/') - on_syntax_error(scanner); - - pj_scan_get_until_chr(scanner, " \t>", &end_name); - - /* Compare name. */ - if (pj_stricmp(&node->name, &end_name) != 0) - on_syntax_error(scanner); - - /* Enclosing '>' */ - if (pj_scan_get_char(scanner) != '>') - on_syntax_error(scanner); - - return node; -} - -PJ_DEF(pj_xml_node*) pj_xml_parse( pj_pool_t *pool, char *msg, pj_size_t len) -{ - pj_xml_node *node = NULL; - pj_scanner scanner; - PJ_USE_EXCEPTION; - - if (!msg || !len || !pool) - return NULL; - - pj_scan_init( &scanner, msg, len, - PJ_SCAN_AUTOSKIP_WS|PJ_SCAN_AUTOSKIP_NEWLINE, - &on_syntax_error); - PJ_TRY { - node = xml_parse_node(pool, &scanner); - } - PJ_DEFAULT { - PJ_LOG(4,(THIS_FILE, "Syntax error parsing XML in line %d column %d", - scanner.line, scanner.col)); - } - PJ_END; - pj_scan_fini( &scanner ); - return node; -} - -/* This is a recursive function. */ -static int xml_print_node( const pj_xml_node *node, int indent, - char *buf, pj_size_t len ) -{ - int i; - char *p = buf; - pj_xml_attr *attr; - pj_xml_node *sub_node; - -#define SIZE_LEFT() ((int)(len - (p-buf))) - - PJ_CHECK_STACK(); - - /* Print name. */ - if (SIZE_LEFT() < node->name.slen + indent + 5) - return -1; - for (i=0; iname.ptr, node->name.slen); - p += node->name.slen; - - /* Print attributes. */ - attr = node->attr_head.next; - while (attr != &node->attr_head) { - - if (SIZE_LEFT() < attr->name.slen + attr->value.slen + 4) - return -1; - - *p++ = ' '; - - /* Attribute name. */ - pj_memcpy(p, attr->name.ptr, attr->name.slen); - p += attr->name.slen; - - /* Attribute value. */ - if (attr->value.slen) { - *p++ = '='; - *p++ = '"'; - pj_memcpy(p, attr->value.ptr, attr->value.slen); - p += attr->value.slen; - *p++ = '"'; - } - - attr = attr->next; - } - - /* Check for empty node. */ - if (node->content.slen==0 && - node->node_head.next==(pj_xml_node*)&node->node_head) - { - *p++ = ' '; - *p++ = '/'; - *p++ = '>'; - return p-buf; - } - - /* Enclosing '>' */ - if (SIZE_LEFT() < 1) return -1; - *p++ = '>'; - - /* Print sub nodes. */ - sub_node = node->node_head.next; - while (sub_node != (pj_xml_node*)&node->node_head) { - int printed; - - if (SIZE_LEFT() < indent + 3) - return -1; - //*p++ = '\r'; - *p++ = '\n'; - - printed = xml_print_node(sub_node, indent + 1, p, SIZE_LEFT()); - if (printed < 0) - return -1; - - p += printed; - sub_node = sub_node->next; - } - - /* Content. */ - if (node->content.slen) { - if (SIZE_LEFT() < node->content.slen) return -1; - pj_memcpy(p, node->content.ptr, node->content.slen); - p += node->content.slen; - } - - /* Enclosing node. */ - if (node->node_head.next != (pj_xml_node*)&node->node_head) { - if (SIZE_LEFT() < node->name.slen + 5 + indent) - return -1; - //*p++ = '\r'; - *p++ = '\n'; - for (i=0; iname.slen + 3) - return -1; - } - *p++ = '<'; - *p++ = '/'; - pj_memcpy(p, node->name.ptr, node->name.slen); - p += node->name.slen; - *p++ = '>'; - -#undef SIZE_LEFT - - return p - buf; -} - -PJ_DEF(int) pj_xml_print(const pj_xml_node *node, char *buf, pj_size_t len, - pj_bool_t include_prolog) -{ - int prolog_len = 0; - int printed; - - if (!node || !buf || !len) - return 0; - - if (include_prolog) { - pj_str_t prolog = {"\n", 39}; - if ((int)len < prolog.slen) - return -1; - pj_memcpy(buf, prolog.ptr, prolog.slen); - prolog_len = prolog.slen; - } - - printed = xml_print_node(node, 0, buf+prolog_len, len-prolog_len) + prolog_len; - if (printed > 0 && len-printed >= 1) { - buf[printed++] = '\n'; - } - return printed; -} - - -PJ_DEF(void) pj_xml_add_node( pj_xml_node *parent, pj_xml_node *node ) -{ - pj_list_insert_before(&parent->node_head, node); -} - -PJ_DEF(void) pj_xml_add_attr( pj_xml_node *node, pj_xml_attr *attr ) -{ - pj_list_insert_before(&node->attr_head, attr); -} - -PJ_DEF(pj_xml_node*) pj_xml_find_node(pj_xml_node *parent, const pj_str_t *name) -{ - pj_xml_node *node = parent->node_head.next; - - PJ_CHECK_STACK(); - - while (node != (void*)&parent->node_head) { - if (pj_stricmp(&node->name, name) == 0) - return node; - node = node->next; - } - return NULL; -} - - -PJ_DEF(pj_xml_node*) pj_xml_find_next_node( pj_xml_node *parent, pj_xml_node *node, - const pj_str_t *name) -{ - PJ_CHECK_STACK(); - - node = node->next; - while (node != (void*)&parent->node_head) { - if (pj_stricmp(&node->name, name) == 0) - return node; - node = node->next; - } - return NULL; -} - - -PJ_DEF(pj_xml_attr*) pj_xml_find_attr( pj_xml_node *node, const pj_str_t *name, - const pj_str_t *value) -{ - pj_xml_attr *attr = node->attr_head.next; - while (attr != (void*)&node->attr_head) { - if (pj_stricmp(&attr->name, name)==0) { - if (value) { - if (pj_stricmp(&attr->value, value)==0) - return attr; - } else { - return attr; - } - } - attr = attr->next; - } - return NULL; -} - - - -PJ_DEF(pj_xml_node*) pj_xml_find( pj_xml_node *parent, const pj_str_t *name, - const void *data, - pj_bool_t (*match)(pj_xml_node *, const void*)) -{ - pj_xml_node *head = (void*)&parent->node_head, *node = head->next; - - while (node != (void*)head) { - if (name && pj_stricmp(&node->name, name)==0) { - if (match) { - if (match(node, data)) - return node; - } else { - return node; - } - } - node = node->next; - } - return NULL; -} - +/* $Header: /pjproject-0.3/pjlib/src/pj/xml.c 9 10/14/05 12:26a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pj/xml.c $ + * + * 9 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 8 9/21/05 1:39p Bennylp + * Periodic checkin for backup. + * + * 7 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + */ +#include +#include +#include +#include +#include +#include +#include + +#define EX_SYNTAX_ERROR 12 +#define THIS_FILE "xml.c" + +static void on_syntax_error(struct pj_scanner *scanner) +{ + PJ_UNUSED_ARG(scanner); + PJ_THROW(EX_SYNTAX_ERROR); +} + +static pj_xml_node *alloc_node( pj_pool_t *pool ) +{ + pj_xml_node *node; + + node = pj_pool_calloc(pool, 1, sizeof(pj_xml_node)); + pj_list_init( &node->attr_head ); + pj_list_init( &node->node_head ); + + return node; +} + +static pj_xml_attr *alloc_attr( pj_pool_t *pool ) +{ + return pj_pool_calloc(pool, 1, sizeof(pj_xml_attr)); +} + +/* This is a recursive function! */ +static pj_xml_node *xml_parse_node( pj_pool_t *pool, pj_scanner *scanner) +{ + pj_xml_node *node; + pj_str_t end_name; + + PJ_CHECK_STACK(); + + if (*scanner->curptr != '<') + on_syntax_error(scanner); + + /* Handle Processing Instructino (PI) construct (i.e. "curptr == '<' && *(scanner->curptr+1) == '?') { + pj_scan_advance_n(scanner, 2, PJ_FALSE); + for (;;) { + pj_str_t dummy; + pj_scan_get_until_ch(scanner, '?', &dummy); + if (*scanner->curptr=='?' && *(scanner->curptr+1)=='>') { + pj_scan_advance_n(scanner, 2, PJ_TRUE); + break; + } else { + pj_scan_advance_n(scanner, 1, PJ_FALSE); + } + } + return xml_parse_node(pool, scanner); + } + + /* Handle comments construct (i.e. "", 3) == 0) { + pj_scan_advance_n(scanner, 3, PJ_TRUE); + break; + } else { + pj_scan_advance_n(scanner, 1, PJ_FALSE); + } + } + return xml_parse_node(pool, scanner); + } + + /* Alloc node. */ + node = alloc_node(pool); + + /* Get '<' */ + pj_scan_get_char(scanner); + + /* Get node name. */ + pj_scan_get_until_chr( scanner, " />\t", &node->name); + + /* Get attributes. */ + while (*scanner->curptr != '>' && *scanner->curptr != '/') { + pj_xml_attr *attr = alloc_attr(pool); + + pj_scan_get_until_chr( scanner, "=> \t", &attr->name); + if (*scanner->curptr == '=') { + pj_scan_get_char( scanner ); + pj_scan_get_quote(scanner, '"', '"', &attr->value); + /* remove quote characters */ + ++attr->value.ptr; + attr->value.slen -= 2; + } + + pj_list_insert_before( &node->attr_head, attr ); + } + + if (*scanner->curptr == '/') { + pj_scan_get_char(scanner); + if (pj_scan_get_char(scanner) != '>') + on_syntax_error(scanner); + return node; + } + + /* Enclosing bracket. */ + if (pj_scan_get_char(scanner) != '>') + on_syntax_error(scanner); + + /* Sub nodes. */ + while (*scanner->curptr == '<' && *(scanner->curptr+1) != '/') { + pj_xml_node *sub_node = xml_parse_node(pool, scanner); + pj_list_insert_before( &node->node_head, sub_node ); + } + + /* Content. */ + if (!pj_scan_is_eof(scanner) && *scanner->curptr != '<') { + pj_scan_get_until_ch(scanner, '<', &node->content); + } + + /* Enclosing node. */ + if (pj_scan_get_char(scanner) != '<' || pj_scan_get_char(scanner) != '/') + on_syntax_error(scanner); + + pj_scan_get_until_chr(scanner, " \t>", &end_name); + + /* Compare name. */ + if (pj_stricmp(&node->name, &end_name) != 0) + on_syntax_error(scanner); + + /* Enclosing '>' */ + if (pj_scan_get_char(scanner) != '>') + on_syntax_error(scanner); + + return node; +} + +PJ_DEF(pj_xml_node*) pj_xml_parse( pj_pool_t *pool, char *msg, pj_size_t len) +{ + pj_xml_node *node = NULL; + pj_scanner scanner; + PJ_USE_EXCEPTION; + + if (!msg || !len || !pool) + return NULL; + + pj_scan_init( &scanner, msg, len, + PJ_SCAN_AUTOSKIP_WS|PJ_SCAN_AUTOSKIP_NEWLINE, + &on_syntax_error); + PJ_TRY { + node = xml_parse_node(pool, &scanner); + } + PJ_DEFAULT { + PJ_LOG(4,(THIS_FILE, "Syntax error parsing XML in line %d column %d", + scanner.line, scanner.col)); + } + PJ_END; + pj_scan_fini( &scanner ); + return node; +} + +/* This is a recursive function. */ +static int xml_print_node( const pj_xml_node *node, int indent, + char *buf, pj_size_t len ) +{ + int i; + char *p = buf; + pj_xml_attr *attr; + pj_xml_node *sub_node; + +#define SIZE_LEFT() ((int)(len - (p-buf))) + + PJ_CHECK_STACK(); + + /* Print name. */ + if (SIZE_LEFT() < node->name.slen + indent + 5) + return -1; + for (i=0; iname.ptr, node->name.slen); + p += node->name.slen; + + /* Print attributes. */ + attr = node->attr_head.next; + while (attr != &node->attr_head) { + + if (SIZE_LEFT() < attr->name.slen + attr->value.slen + 4) + return -1; + + *p++ = ' '; + + /* Attribute name. */ + pj_memcpy(p, attr->name.ptr, attr->name.slen); + p += attr->name.slen; + + /* Attribute value. */ + if (attr->value.slen) { + *p++ = '='; + *p++ = '"'; + pj_memcpy(p, attr->value.ptr, attr->value.slen); + p += attr->value.slen; + *p++ = '"'; + } + + attr = attr->next; + } + + /* Check for empty node. */ + if (node->content.slen==0 && + node->node_head.next==(pj_xml_node*)&node->node_head) + { + *p++ = ' '; + *p++ = '/'; + *p++ = '>'; + return p-buf; + } + + /* Enclosing '>' */ + if (SIZE_LEFT() < 1) return -1; + *p++ = '>'; + + /* Print sub nodes. */ + sub_node = node->node_head.next; + while (sub_node != (pj_xml_node*)&node->node_head) { + int printed; + + if (SIZE_LEFT() < indent + 3) + return -1; + //*p++ = '\r'; + *p++ = '\n'; + + printed = xml_print_node(sub_node, indent + 1, p, SIZE_LEFT()); + if (printed < 0) + return -1; + + p += printed; + sub_node = sub_node->next; + } + + /* Content. */ + if (node->content.slen) { + if (SIZE_LEFT() < node->content.slen) return -1; + pj_memcpy(p, node->content.ptr, node->content.slen); + p += node->content.slen; + } + + /* Enclosing node. */ + if (node->node_head.next != (pj_xml_node*)&node->node_head) { + if (SIZE_LEFT() < node->name.slen + 5 + indent) + return -1; + //*p++ = '\r'; + *p++ = '\n'; + for (i=0; iname.slen + 3) + return -1; + } + *p++ = '<'; + *p++ = '/'; + pj_memcpy(p, node->name.ptr, node->name.slen); + p += node->name.slen; + *p++ = '>'; + +#undef SIZE_LEFT + + return p - buf; +} + +PJ_DEF(int) pj_xml_print(const pj_xml_node *node, char *buf, pj_size_t len, + pj_bool_t include_prolog) +{ + int prolog_len = 0; + int printed; + + if (!node || !buf || !len) + return 0; + + if (include_prolog) { + pj_str_t prolog = {"\n", 39}; + if ((int)len < prolog.slen) + return -1; + pj_memcpy(buf, prolog.ptr, prolog.slen); + prolog_len = prolog.slen; + } + + printed = xml_print_node(node, 0, buf+prolog_len, len-prolog_len) + prolog_len; + if (printed > 0 && len-printed >= 1) { + buf[printed++] = '\n'; + } + return printed; +} + + +PJ_DEF(void) pj_xml_add_node( pj_xml_node *parent, pj_xml_node *node ) +{ + pj_list_insert_before(&parent->node_head, node); +} + +PJ_DEF(void) pj_xml_add_attr( pj_xml_node *node, pj_xml_attr *attr ) +{ + pj_list_insert_before(&node->attr_head, attr); +} + +PJ_DEF(pj_xml_node*) pj_xml_find_node(pj_xml_node *parent, const pj_str_t *name) +{ + pj_xml_node *node = parent->node_head.next; + + PJ_CHECK_STACK(); + + while (node != (void*)&parent->node_head) { + if (pj_stricmp(&node->name, name) == 0) + return node; + node = node->next; + } + return NULL; +} + + +PJ_DEF(pj_xml_node*) pj_xml_find_next_node( pj_xml_node *parent, pj_xml_node *node, + const pj_str_t *name) +{ + PJ_CHECK_STACK(); + + node = node->next; + while (node != (void*)&parent->node_head) { + if (pj_stricmp(&node->name, name) == 0) + return node; + node = node->next; + } + return NULL; +} + + +PJ_DEF(pj_xml_attr*) pj_xml_find_attr( pj_xml_node *node, const pj_str_t *name, + const pj_str_t *value) +{ + pj_xml_attr *attr = node->attr_head.next; + while (attr != (void*)&node->attr_head) { + if (pj_stricmp(&attr->name, name)==0) { + if (value) { + if (pj_stricmp(&attr->value, value)==0) + return attr; + } else { + return attr; + } + } + attr = attr->next; + } + return NULL; +} + + + +PJ_DEF(pj_xml_node*) pj_xml_find( pj_xml_node *parent, const pj_str_t *name, + const void *data, + pj_bool_t (*match)(pj_xml_node *, const void*)) +{ + pj_xml_node *head = (void*)&parent->node_head, *node = head->next; + + while (node != (void*)head) { + if (name && pj_stricmp(&node->name, name)==0) { + if (match) { + if (match(node, data)) + return node; + } else { + return node; + } + } + node = node->next; + } + return NULL; +} + diff --git a/pjlib/src/pjlib-samples/except.c b/pjlib/src/pjlib-samples/except.c index c6b7f556..e3648d20 100644 --- a/pjlib/src/pjlib-samples/except.c +++ b/pjlib/src/pjlib-samples/except.c @@ -1,79 +1,79 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-samples/except.c 2 10/14/05 12:26a Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pjlib-samples/except.c $ - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 10/10/05 3:16p Bennylp - * Created. - * - */ -#include -#include -#include -#include - -/** - * \page page_pjlib_samples_except_c Example: Exception Handling - * - * Below is sample program to demonstrate how to use exception handling. - * - * \includelineno pjlib-samples/except.c - */ - -static pj_exception_id_t NO_MEMORY, OTHER_EXCEPTION; - -static void randomly_throw_exception() -{ - if (pj_rand() % 2) - PJ_THROW(OTHER_EXCEPTION); -} - -static void *my_malloc(size_t size) -{ - void *ptr = malloc(size); - if (!ptr) - PJ_THROW(NO_MEMORY); - return ptr; -} - -static int test_exception() -{ - PJ_USE_EXCEPTION; - - PJ_TRY { - void *data = my_malloc(200); - free(data); - randomly_throw_exception(); - } - PJ_CATCH( NO_MEMORY ) { - puts("Can't allocate memory"); - return 0; - } - PJ_DEFAULT { - pj_exception_id_t x_id; - - x_id = PJ_GET_EXCEPTION(); - printf("Caught exception %d (%s)\n", - x_id, pj_exception_id_name(x_id)); - } - PJ_END - return 1; -} - -int main() -{ - pj_status_t rc; - - // Error handling is omited for clarity. - - rc = pj_init(); - - rc = pj_exception_id_alloc("No Memory", &NO_MEMORY); - rc = pj_exception_id_alloc("Other Exception", &OTHER_EXCEPTION); - - return test_exception(); -} - +/* $Header: /pjproject-0.3/pjlib/src/pjlib-samples/except.c 2 10/14/05 12:26a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pjlib-samples/except.c $ + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 10/10/05 3:16p Bennylp + * Created. + * + */ +#include +#include +#include +#include + +/** + * \page page_pjlib_samples_except_c Example: Exception Handling + * + * Below is sample program to demonstrate how to use exception handling. + * + * \includelineno pjlib-samples/except.c + */ + +static pj_exception_id_t NO_MEMORY, OTHER_EXCEPTION; + +static void randomly_throw_exception() +{ + if (pj_rand() % 2) + PJ_THROW(OTHER_EXCEPTION); +} + +static void *my_malloc(size_t size) +{ + void *ptr = malloc(size); + if (!ptr) + PJ_THROW(NO_MEMORY); + return ptr; +} + +static int test_exception() +{ + PJ_USE_EXCEPTION; + + PJ_TRY { + void *data = my_malloc(200); + free(data); + randomly_throw_exception(); + } + PJ_CATCH( NO_MEMORY ) { + puts("Can't allocate memory"); + return 0; + } + PJ_DEFAULT { + pj_exception_id_t x_id; + + x_id = PJ_GET_EXCEPTION(); + printf("Caught exception %d (%s)\n", + x_id, pj_exception_id_name(x_id)); + } + PJ_END + return 1; +} + +int main() +{ + pj_status_t rc; + + // Error handling is omited for clarity. + + rc = pj_init(); + + rc = pj_exception_id_alloc("No Memory", &NO_MEMORY); + rc = pj_exception_id_alloc("Other Exception", &OTHER_EXCEPTION); + + return test_exception(); +} + diff --git a/pjlib/src/pjlib-samples/list.c b/pjlib/src/pjlib-samples/list.c index 74e783f5..11518ebd 100644 --- a/pjlib/src/pjlib-samples/list.c +++ b/pjlib/src/pjlib-samples/list.c @@ -1,66 +1,66 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-samples/list.c 2 10/14/05 12:26a Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pjlib-samples/list.c $ - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 10/10/05 5:12p Bennylp - * Created. - * - */ - -#include -#include -#include - -/** - * \page page_pjlib_samples_list_c Example: List Manipulation - * - * Below is sample program to demonstrate how to manipulate linked list. - * - * \includelineno pjlib-samples/list.c - */ - -struct my_node -{ - // This must be the first member declared in the struct! - PJ_DECL_LIST_MEMBER(struct my_node) - int value; -}; - - -int main() -{ - struct my_node nodes[10]; - struct my_node list; - struct my_node *it; - int i; - - // Initialize the list as empty. - pj_list_init(&list); - - // Insert nodes. - for (i=0; i<10; ++i) { - nodes[i].value = i; - pj_list_insert_before(&list, &nodes[i]); - } - - // Iterate list nodes. - it = list.next; - while (it != &list) { - PJ_LOG(3,("list", "value = %d", it->value)); - it = it->next; - } - - // Erase all nodes. - for (i=0; i<10; ++i) { - pj_list_erase(&nodes[i]); - } - - // List must be empty by now. - pj_assert( pj_list_empty(&list) ); - - return 0; -}; +/* $Header: /pjproject-0.3/pjlib/src/pjlib-samples/list.c 2 10/14/05 12:26a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pjlib-samples/list.c $ + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 10/10/05 5:12p Bennylp + * Created. + * + */ + +#include +#include +#include + +/** + * \page page_pjlib_samples_list_c Example: List Manipulation + * + * Below is sample program to demonstrate how to manipulate linked list. + * + * \includelineno pjlib-samples/list.c + */ + +struct my_node +{ + // This must be the first member declared in the struct! + PJ_DECL_LIST_MEMBER(struct my_node) + int value; +}; + + +int main() +{ + struct my_node nodes[10]; + struct my_node list; + struct my_node *it; + int i; + + // Initialize the list as empty. + pj_list_init(&list); + + // Insert nodes. + for (i=0; i<10; ++i) { + nodes[i].value = i; + pj_list_insert_before(&list, &nodes[i]); + } + + // Iterate list nodes. + it = list.next; + while (it != &list) { + PJ_LOG(3,("list", "value = %d", it->value)); + it = it->next; + } + + // Erase all nodes. + for (i=0; i<10; ++i) { + pj_list_erase(&nodes[i]); + } + + // List must be empty by now. + pj_assert( pj_list_empty(&list) ); + + return 0; +}; diff --git a/pjlib/src/pjlib-samples/log.c b/pjlib/src/pjlib-samples/log.c index b90c71d0..196bf663 100644 --- a/pjlib/src/pjlib-samples/log.c +++ b/pjlib/src/pjlib-samples/log.c @@ -1,36 +1,36 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-samples/log.c 2 10/14/05 12:26a Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pjlib-samples/log.c $ - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 10/10/05 3:16p Bennylp - * Created. - * - */ -#include - -/** - * \page page_pjlib_samples_log_c Example: Log, Hello World - * - * Very simple program to write log. - * - * \includelineno pjlib-samples/log.c - */ - -int main() -{ - pj_status_t rc; - - // Error handling omited for clarity - - // Must initialize PJLIB first! - rc = pj_init(); - - PJ_LOG(3, ("main.c", "Hello world!")); - - return 0; -} - +/* $Header: /pjproject-0.3/pjlib/src/pjlib-samples/log.c 2 10/14/05 12:26a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pjlib-samples/log.c $ + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 10/10/05 3:16p Bennylp + * Created. + * + */ +#include + +/** + * \page page_pjlib_samples_log_c Example: Log, Hello World + * + * Very simple program to write log. + * + * \includelineno pjlib-samples/log.c + */ + +int main() +{ + pj_status_t rc; + + // Error handling omited for clarity + + // Must initialize PJLIB first! + rc = pj_init(); + + PJ_LOG(3, ("main.c", "Hello world!")); + + return 0; +} + diff --git a/pjlib/src/pjlib-test/atomic.c b/pjlib/src/pjlib-test/atomic.c index 0a1ebb7d..a68db254 100644 --- a/pjlib/src/pjlib-test/atomic.c +++ b/pjlib/src/pjlib-test/atomic.c @@ -1,94 +1,94 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/atomic.c 2 10/14/05 12:26a Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pjlib-test/atomic.c $ - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 10/07/05 9:49p Bennylp - * Created. - * - */ -#include "test.h" -#include - -/** - * \page page_pjlib_atomic_test Test: Atomic Variable - * - * This file provides implementation of \b atomic_test(). It tests the - * functionality of the atomic variable API. - * - * \section atomic_test_sec Scope of the Test - * - * API tested: - * - pj_atomic_create() - * - pj_atomic_get() - * - pj_atomic_inc() - * - pj_atomic_dec() - * - pj_atomic_set() - * - pj_atomic_destroy() - * - * - * This file is pjlib-test/atomic.c - * - * \include pjlib-test/atomic.c - */ - - -#if INCLUDE_ATOMIC_TEST - -int atomic_test(void) -{ - pj_pool_t *pool; - pj_atomic_t *atomic_var; - pj_status_t rc; - - pool = pj_pool_create(mem, NULL, 4096, 0, NULL); - if (!pool) - return -10; - - /* create() */ - rc = pj_atomic_create(pool, 111, &atomic_var); - if (rc != 0) { - return -20; - } - - /* get: check the value. */ - if (pj_atomic_get(atomic_var) != 111) - return -30; - - /* increment. */ - if (pj_atomic_inc(atomic_var) != 112) - return -40; - - /* decrement. */ - if (pj_atomic_dec(atomic_var) != 111) - return -50; - - /* set */ - if (pj_atomic_set(atomic_var, 211) != 111) - return -60; - - /* check the value again. */ - if (pj_atomic_get(atomic_var) != 211) - return -70; - - /* destroy */ - rc = pj_atomic_destroy(atomic_var); - if (rc != 0) - return -80; - - pj_pool_release(pool); - - return 0; -} - - -#else -/* To prevent warning about "translation unit is empty" - * when this test is disabled. - */ -int dummy_atomic_test; -#endif /* INCLUDE_ATOMIC_TEST */ - +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/atomic.c 2 10/14/05 12:26a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pjlib-test/atomic.c $ + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 10/07/05 9:49p Bennylp + * Created. + * + */ +#include "test.h" +#include + +/** + * \page page_pjlib_atomic_test Test: Atomic Variable + * + * This file provides implementation of \b atomic_test(). It tests the + * functionality of the atomic variable API. + * + * \section atomic_test_sec Scope of the Test + * + * API tested: + * - pj_atomic_create() + * - pj_atomic_get() + * - pj_atomic_inc() + * - pj_atomic_dec() + * - pj_atomic_set() + * - pj_atomic_destroy() + * + * + * This file is pjlib-test/atomic.c + * + * \include pjlib-test/atomic.c + */ + + +#if INCLUDE_ATOMIC_TEST + +int atomic_test(void) +{ + pj_pool_t *pool; + pj_atomic_t *atomic_var; + pj_status_t rc; + + pool = pj_pool_create(mem, NULL, 4096, 0, NULL); + if (!pool) + return -10; + + /* create() */ + rc = pj_atomic_create(pool, 111, &atomic_var); + if (rc != 0) { + return -20; + } + + /* get: check the value. */ + if (pj_atomic_get(atomic_var) != 111) + return -30; + + /* increment. */ + if (pj_atomic_inc(atomic_var) != 112) + return -40; + + /* decrement. */ + if (pj_atomic_dec(atomic_var) != 111) + return -50; + + /* set */ + if (pj_atomic_set(atomic_var, 211) != 111) + return -60; + + /* check the value again. */ + if (pj_atomic_get(atomic_var) != 211) + return -70; + + /* destroy */ + rc = pj_atomic_destroy(atomic_var); + if (rc != 0) + return -80; + + pj_pool_release(pool); + + return 0; +} + + +#else +/* To prevent warning about "translation unit is empty" + * when this test is disabled. + */ +int dummy_atomic_test; +#endif /* INCLUDE_ATOMIC_TEST */ + diff --git a/pjlib/src/pjlib-test/echo_clt.c b/pjlib/src/pjlib-test/echo_clt.c index 565d5607..7a31f0d9 100644 --- a/pjlib/src/pjlib-test/echo_clt.c +++ b/pjlib/src/pjlib-test/echo_clt.c @@ -1,267 +1,277 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/echo_clt.c 3 10/29/05 10:25p Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pjlib-test/echo_clt.c $ - * - * 3 10/29/05 10:25p Bennylp - * Tested. - * - * 2 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 1 10/24/05 11:28a Bennylp - * Created. - * - */ -#include "test.h" -#include - -#if INCLUDE_ECHO_CLIENT - -enum { BUF_SIZE = 512 }; - -struct client -{ - int sock_type; - const char *server; - int port; -}; - -static pj_sem_t *sem; -static pj_mutex_t *mutex; -static pj_size_t total_bw; -static unsigned total_poster; -static pj_time_val first_report; - -#define MSEC_PRINT_DURATION 1000 - -static int wait_socket(pj_sock_t sock, unsigned msec_timeout) -{ - pj_fd_set_t fdset; - pj_time_val timeout; - - timeout.sec = 0; - timeout.msec = msec_timeout; - pj_time_val_normalize(&timeout); - - PJ_FD_ZERO(&fdset); - PJ_FD_SET(sock, &fdset); - - return pj_sock_select(1, &fdset, NULL, NULL, &timeout); -} - -static int echo_client_thread(void *arg) -{ - pj_sock_t sock; - char send_buf[BUF_SIZE]; - char recv_buf[BUF_SIZE]; - pj_sockaddr_in addr; - pj_str_t s; - pj_status_t rc; - struct client *client = arg; - pj_status_t last_recv_err = PJ_SUCCESS, last_send_err = PJ_SUCCESS; - - pj_time_val last_report, next_report; - pj_size_t thread_total; - - rc = app_socket(PJ_AF_INET, client->sock_type, 0, -1, &sock); - if (rc != PJ_SUCCESS) { - app_perror("...unable to create socket", rc); - return -10; - } - - rc = pj_sockaddr_in_init( &addr, pj_cstr(&s, client->server), - (pj_uint16_t)client->port); - if (rc != PJ_SUCCESS) { - app_perror("...unable to resolve server", rc); - return -15; - } - - rc = pj_sock_connect(sock, &addr, sizeof(addr)); - if (rc != PJ_SUCCESS) { - app_perror("...connect() error", rc); - pj_sock_close(sock); - return -20; - } - - pj_create_random_string(send_buf, BUF_SIZE); - thread_total = 0; - - /* Give other thread chance to initialize themselves! */ - pj_thread_sleep(500); - - pj_gettimeofday(&last_report); - next_report = first_report; - - //PJ_LOG(3,("", "...thread %p running", pj_thread_this())); - - for (;;) { - int rc; - pj_ssize_t bytes; - pj_time_val now; - - /* Send a packet. */ - bytes = BUF_SIZE; - rc = pj_sock_send(sock, send_buf, &bytes, 0); - if (rc != PJ_SUCCESS || bytes != BUF_SIZE) { - if (rc != last_send_err) { - app_perror("...send() error", rc); - PJ_LOG(3,("", "...ignoring subsequent error..")); - last_send_err = rc; - pj_thread_sleep(100); - } - continue; - } - - rc = wait_socket(sock, 500); - if (rc == 0) { - PJ_LOG(3,("", "...timeout")); - } else { - /* Receive back the original packet. */ - bytes = 0; - do { - pj_ssize_t received = BUF_SIZE - bytes; - rc = pj_sock_recv(sock, recv_buf+bytes, &received, 0); - if (rc != PJ_SUCCESS || received == 0) { - if (rc != last_recv_err) { - app_perror("...recv() error", rc); - PJ_LOG(3,("", "...ignoring subsequent error..")); - last_recv_err = rc; - pj_thread_sleep(100); - } - bytes = 0; - break; - } - bytes += received; - } while (bytes != BUF_SIZE); - } - - /* Accumulate total received. */ - thread_total = thread_total + bytes; - - /* Report current bandwidth on due. */ - pj_gettimeofday(&now); - - if (PJ_TIME_VAL_GTE(now, next_report)) { - pj_uint32_t bw; - pj_bool_t signal_parent = 0; - pj_time_val duration; - pj_uint32_t msec; - - duration = now; - PJ_TIME_VAL_SUB(duration, last_report); - msec = PJ_TIME_VAL_MSEC(duration); - - bw = thread_total * 1000 / msec; - - /* Post result to parent */ - pj_mutex_lock(mutex); - total_bw += bw; - total_poster++; - //PJ_LOG(3,("", "...thread %p posting result", pj_thread_this())); - if (total_poster >= ECHO_CLIENT_MAX_THREADS) - signal_parent = 1; - pj_mutex_unlock(mutex); - - thread_total = 0; - last_report = now; - next_report.sec++; - - if (signal_parent) { - pj_sem_post(sem); - } - - pj_thread_sleep(0); - } - - if (bytes == 0) - continue; - - if (pj_memcmp(send_buf, recv_buf, BUF_SIZE) != 0) { - PJ_LOG(3,("", "...error: buffer has changed!")); - break; - } - } - - pj_sock_close(sock); - return 0; -} - -int echo_client(int sock_type, const char *server, int port) -{ - pj_pool_t *pool; - pj_thread_t *thread[ECHO_CLIENT_MAX_THREADS]; - pj_status_t rc; - struct client client; - int i; - - client.sock_type = sock_type; - client.server = server; - client.port = port; - - pool = pj_pool_create( mem, NULL, 4000, 4000, NULL ); - - rc = pj_sem_create(pool, NULL, 0, ECHO_CLIENT_MAX_THREADS+1, &sem); - if (rc != PJ_SUCCESS) { - PJ_LOG(3,("", "...error: unable to create semaphore", rc)); - return -10; - } - - rc = pj_mutex_create_simple(pool, NULL, &mutex); - if (rc != PJ_SUCCESS) { - PJ_LOG(3,("", "...error: unable to create mutex", rc)); - return -20; - } - - /* - rc = pj_atomic_create(pool, 0, &atom); - if (rc != PJ_SUCCESS) { - PJ_LOG(3,("", "...error: unable to create atomic variable", rc)); - return -30; - } - */ - - PJ_LOG(3,("", "Echo client started")); - PJ_LOG(3,("", " Destination: %s:%d", - ECHO_SERVER_ADDRESS, ECHO_SERVER_START_PORT)); - PJ_LOG(3,("", " Press Ctrl-C to exit")); - - pj_gettimeofday(&first_report); - first_report.sec += 2; - - for (i=0; i + +#if INCLUDE_ECHO_CLIENT + +enum { BUF_SIZE = 512 }; + +struct client +{ + int sock_type; + const char *server; + int port; +}; + +static pj_sem_t *sem; +static pj_mutex_t *mutex; +static pj_size_t total_bw; +static unsigned total_poster; +static pj_time_val first_report; + +#define MSEC_PRINT_DURATION 1000 + +static int wait_socket(pj_sock_t sock, unsigned msec_timeout) +{ + pj_fd_set_t fdset; + pj_time_val timeout; + + timeout.sec = 0; + timeout.msec = msec_timeout; + pj_time_val_normalize(&timeout); + + PJ_FD_ZERO(&fdset); + PJ_FD_SET(sock, &fdset); + + return pj_sock_select(FD_SETSIZE, &fdset, NULL, NULL, &timeout); +} + +static int echo_client_thread(void *arg) +{ + pj_sock_t sock; + char send_buf[BUF_SIZE]; + char recv_buf[BUF_SIZE]; + pj_sockaddr_in addr; + pj_str_t s; + pj_status_t rc; + struct client *client = arg; + pj_status_t last_recv_err = PJ_SUCCESS, last_send_err = PJ_SUCCESS; + + pj_time_val last_report, next_report; + pj_size_t thread_total; + + rc = app_socket(PJ_AF_INET, client->sock_type, 0, -1, &sock); + if (rc != PJ_SUCCESS) { + app_perror("...unable to create socket", rc); + return -10; + } + + rc = pj_sockaddr_in_init( &addr, pj_cstr(&s, client->server), + (pj_uint16_t)client->port); + if (rc != PJ_SUCCESS) { + app_perror("...unable to resolve server", rc); + return -15; + } + + rc = pj_sock_connect(sock, &addr, sizeof(addr)); + if (rc != PJ_SUCCESS) { + app_perror("...connect() error", rc); + pj_sock_close(sock); + return -20; + } + + PJ_LOG(3,("", "...socket connected to %s:%d", + pj_inet_ntoa(addr.sin_addr), + pj_ntohs(addr.sin_port))); + + pj_create_random_string(send_buf, BUF_SIZE); + thread_total = 0; + + /* Give other thread chance to initialize themselves! */ + pj_thread_sleep(500); + + pj_gettimeofday(&last_report); + next_report = first_report; + + //PJ_LOG(3,("", "...thread %p running", pj_thread_this())); + + for (;;) { + int rc; + pj_ssize_t bytes; + pj_time_val now; + + /* Send a packet. */ + bytes = BUF_SIZE; + rc = pj_sock_send(sock, send_buf, &bytes, 0); + if (rc != PJ_SUCCESS || bytes != BUF_SIZE) { + if (rc != last_send_err) { + app_perror("...send() error", rc); + PJ_LOG(3,("", "...ignoring subsequent error..")); + last_send_err = rc; + pj_thread_sleep(100); + } + continue; + } + + rc = wait_socket(sock, 500); + if (rc == 0) { + PJ_LOG(3,("", "...timeout")); + bytes = 0; + } else if (rc < 0) { + rc = pj_get_netos_error(); + app_perror("...select() error", rc); + break; + } else { + /* Receive back the original packet. */ + bytes = 0; + do { + pj_ssize_t received = BUF_SIZE - bytes; + rc = pj_sock_recv(sock, recv_buf+bytes, &received, 0); + if (rc != PJ_SUCCESS || received == 0) { + if (rc != last_recv_err) { + app_perror("...recv() error", rc); + PJ_LOG(3,("", "...ignoring subsequent error..")); + last_recv_err = rc; + pj_thread_sleep(100); + } + bytes = 0; + received = 0; + break; + } + bytes += received; + } while (bytes != BUF_SIZE && bytes != 0); + } + + /* Accumulate total received. */ + thread_total = thread_total + bytes; + + /* Report current bandwidth on due. */ + pj_gettimeofday(&now); + + if (PJ_TIME_VAL_GTE(now, next_report)) { + pj_uint32_t bw; + pj_bool_t signal_parent = 0; + pj_time_val duration; + pj_uint32_t msec; + + duration = now; + PJ_TIME_VAL_SUB(duration, last_report); + msec = PJ_TIME_VAL_MSEC(duration); + + bw = thread_total * 1000 / msec; + + /* Post result to parent */ + pj_mutex_lock(mutex); + total_bw += bw; + total_poster++; + //PJ_LOG(3,("", "...thread %p posting result", pj_thread_this())); + if (total_poster >= ECHO_CLIENT_MAX_THREADS) + signal_parent = 1; + pj_mutex_unlock(mutex); + + thread_total = 0; + last_report = now; + next_report.sec++; + + if (signal_parent) { + pj_sem_post(sem); + } + + pj_thread_sleep(0); + } + + if (bytes == 0) + continue; + + if (pj_memcmp(send_buf, recv_buf, BUF_SIZE) != 0) { + //PJ_LOG(3,("", "...error: buffer has changed!")); + break; + } + } + + pj_sock_close(sock); + return 0; +} + +int echo_client(int sock_type, const char *server, int port) +{ + pj_pool_t *pool; + pj_thread_t *thread[ECHO_CLIENT_MAX_THREADS]; + pj_status_t rc; + struct client client; + int i; + + client.sock_type = sock_type; + client.server = server; + client.port = port; + + pool = pj_pool_create( mem, NULL, 4000, 4000, NULL ); + + rc = pj_sem_create(pool, NULL, 0, ECHO_CLIENT_MAX_THREADS+1, &sem); + if (rc != PJ_SUCCESS) { + PJ_LOG(3,("", "...error: unable to create semaphore", rc)); + return -10; + } + + rc = pj_mutex_create_simple(pool, NULL, &mutex); + if (rc != PJ_SUCCESS) { + PJ_LOG(3,("", "...error: unable to create mutex", rc)); + return -20; + } + + /* + rc = pj_atomic_create(pool, 0, &atom); + if (rc != PJ_SUCCESS) { + PJ_LOG(3,("", "...error: unable to create atomic variable", rc)); + return -30; + } + */ + + PJ_LOG(3,("", "Echo client started")); + PJ_LOG(3,("", " Destination: %s:%d", + ECHO_SERVER_ADDRESS, ECHO_SERVER_START_PORT)); + PJ_LOG(3,("", " Press Ctrl-C to exit")); + + pj_gettimeofday(&first_report); + first_report.sec += 2; + + for (i=0; i -#include - -#if INCLUDE_ECHO_SERVER - -static pj_bool_t thread_quit_flag; - -struct server -{ - pj_pool_t *pool; - int sock_type; - int thread_count; - pj_ioqueue_t *ioqueue; - pj_sock_t sock; - pj_sock_t client_sock; - pj_ioqueue_key_t *key; - pj_ioqueue_callback cb; - char *buf; - pj_size_t bufsize; - pj_sockaddr_in addr; - int addrlen; - pj_size_t bytes_recv; - pj_timestamp start_time; -}; - -static void on_read_complete(pj_ioqueue_key_t *key, pj_ssize_t bytes_read) -{ - struct server *server = pj_ioqueue_get_user_data(key); - pj_status_t rc; - - if (server->sock_type == PJ_SOCK_DGRAM) { - if (bytes_read > 0) { - /* Send data back to sender. */ - rc = pj_ioqueue_sendto( server->ioqueue, server->key, - server->buf, bytes_read, 0, - &server->addr, server->addrlen); - if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { - app_perror("...sendto() error", rc); - } - } else { - PJ_LOG(3,("", "...read error (bytes_read=%d)", bytes_read)); - } - - /* Start next receive. */ - rc = pj_ioqueue_recvfrom( server->ioqueue, server->key, - server->buf, server->bufsize, 0, - &server->addr, &server->addrlen); - if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { - app_perror("...recvfrom() error", rc); - } - - } - else if (server->sock_type == PJ_SOCK_STREAM) { - if (bytes_read > 0) { - /* Send data back to sender. */ - rc = pj_ioqueue_send( server->ioqueue, server->key, - server->buf, bytes_read, 0); - if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { - app_perror("...send() error", rc); - bytes_read = 0; - } - } - - if (bytes_read <= 0) { - PJ_LOG(3,("", "...tcp closed")); - pj_ioqueue_unregister( server->ioqueue, server->key ); - pj_sock_close( server->sock ); - pj_pool_release( server->pool ); - return; - } - - /* Start next receive. */ - rc = pj_ioqueue_recv( server->ioqueue, server->key, - server->buf, server->bufsize, 0); - if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { - app_perror("...recv() error", rc); - } - } - - /* Add counter. */ - if (bytes_read > 0) { - if (server->bytes_recv == 0) { - pj_get_timestamp(&server->start_time); - server->bytes_recv += bytes_read; - } else { - enum { USECS_IN_SECOND = 1000000 }; - pj_timestamp now; - pj_uint32_t usec_elapsed; - - server->bytes_recv += bytes_read; - - pj_get_timestamp(&now); - usec_elapsed = pj_elapsed_usec(&server->start_time, &now); - if (usec_elapsed > USECS_IN_SECOND) { - if (usec_elapsed < 2 * USECS_IN_SECOND) { - pj_highprec_t bw; - pj_uint32_t bw32; - const char *type_name; - - /* bandwidth(bw) = server->bytes_recv * USECS/elapsed */ - bw = server->bytes_recv; - pj_highprec_mul(bw, USECS_IN_SECOND); - pj_highprec_div(bw, usec_elapsed); - - bw32 = (pj_uint32_t) bw; - - if (server->sock_type==PJ_SOCK_STREAM) - type_name = "tcp"; - else if (server->sock_type==PJ_SOCK_DGRAM) - type_name = "udp"; - else - type_name = "???"; - - PJ_LOG(3,("", - "...[%s:%d (%d threads)] Current bandwidth=%u KBps", - type_name, - ECHO_SERVER_START_PORT+server->thread_count, - server->thread_count, - bw32/1024)); - } - server->start_time = now; - server->bytes_recv = 0; - } - } - } -} - -static void on_accept_complete( pj_ioqueue_key_t *key, pj_sock_t sock, - int status) -{ - struct server *server_server = pj_ioqueue_get_user_data(key); - pj_status_t rc; - - PJ_UNUSED_ARG(sock); - - if (status == 0) { - pj_pool_t *pool; - struct server *new_server; - - pool = pj_pool_create(mem, NULL, 4000, 4000, NULL); - new_server = pj_pool_zalloc(pool, sizeof(struct server)); - - new_server->pool = pool; - new_server->ioqueue = server_server->ioqueue; - new_server->sock_type = server_server->sock_type; - new_server->thread_count = server_server->thread_count; - new_server->sock = server_server->client_sock; - new_server->bufsize = 4096; - new_server->buf = pj_pool_alloc(pool, new_server->bufsize); - new_server->cb = server_server->cb; - - rc = pj_ioqueue_register_sock( new_server->pool, new_server->ioqueue, - new_server->sock, new_server, - &server_server->cb, &new_server->key); - if (rc != PJ_SUCCESS) { - app_perror("...registering new tcp sock", rc); - pj_sock_close(new_server->sock); - pj_pool_release(pool); - thread_quit_flag = 1; - return; - } - - rc = pj_ioqueue_recv( new_server->ioqueue, new_server->key, - new_server->buf, new_server->bufsize, 0); - if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { - app_perror("...recv() error", rc); - pj_sock_close(new_server->sock); - pj_pool_release(pool); - thread_quit_flag = 1; - return; - } - } - - rc = pj_ioqueue_accept( server_server->ioqueue, server_server->key, - &server_server->client_sock, - NULL, NULL, NULL); - if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { - app_perror("...accept() error", rc); - thread_quit_flag = 1; - } -} - -static int thread_proc(void *arg) -{ - pj_ioqueue_t *ioqueue = arg; - - while (!thread_quit_flag) { - pj_time_val timeout; - int count; - - timeout.sec = 0; timeout.msec = 50; - count = pj_ioqueue_poll( ioqueue, &timeout ); - if (count > 0) { - count = 0; - } - } - - return 0; -} - -static int start_echo_server( int sock_type, int port, int thread_count ) -{ - pj_pool_t *pool; - struct server *server; - int i; - pj_status_t rc; - - - pool = pj_pool_create(mem, NULL, 4000, 4000, NULL); - if (!pool) - return -10; - - server = pj_pool_zalloc(pool, sizeof(struct server)); - - server->sock_type = sock_type; - server->thread_count = thread_count; - server->cb.on_read_complete = &on_read_complete; - server->cb.on_accept_complete = &on_accept_complete; - - /* create ioqueue */ - rc = pj_ioqueue_create( pool, 32, thread_count, &server->ioqueue); - if (rc != PJ_SUCCESS) { - app_perror("...error creating ioqueue", rc); - return -20; - } - - /* create and register socket to ioqueue. */ - rc = app_socket(PJ_AF_INET, sock_type, 0, port, &server->sock); - if (rc != PJ_SUCCESS) { - app_perror("...error initializing socket", rc); - return -30; - } - - rc = pj_ioqueue_register_sock( pool, server->ioqueue, - server->sock, - server, &server->cb, - &server->key); - if (rc != PJ_SUCCESS) { - app_perror("...error registering socket to ioqueue", rc); - return -40; - } - - /* create receive buffer. */ - server->bufsize = 4096; - server->buf = pj_pool_alloc(pool, server->bufsize); - - if (sock_type == PJ_SOCK_DGRAM) { - server->addrlen = sizeof(server->addr); - rc = pj_ioqueue_recvfrom( server->ioqueue, server->key, - server->buf, server->bufsize, - 0, - &server->addr, &server->addrlen); - if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { - app_perror("...read error", rc); - return -50; - } - } else { - rc = pj_ioqueue_accept( server->ioqueue, server->key, - &server->client_sock, NULL, NULL, NULL ); - if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { - app_perror("...accept() error", rc); - return -60; - } - } - - /* create threads. */ - - for (i=0; iioqueue, - PJ_THREAD_DEFAULT_STACK_SIZE, 0, &thread); - if (rc != PJ_SUCCESS) { - app_perror("...unable to create thread", rc); - return -70; - } - } - - /* Done. */ - return PJ_SUCCESS; -} - -int echo_server(void) -{ - enum { MAX_THREADS = 4 }; - int sock_types[2]; - int i, j, rc; - - sock_types[0] = PJ_SOCK_DGRAM; - sock_types[1] = PJ_SOCK_STREAM; - - for (i=0; i<2; ++i) { - for (j=0; j +#include + +#if INCLUDE_ECHO_SERVER + +static pj_bool_t thread_quit_flag; + +struct server +{ + pj_pool_t *pool; + int sock_type; + int thread_count; + pj_ioqueue_t *ioqueue; + pj_sock_t sock; + pj_sock_t client_sock; + pj_ioqueue_key_t *key; + pj_ioqueue_callback cb; + char *buf; + pj_size_t bufsize; + pj_sockaddr_in addr; + int addrlen; + pj_size_t bytes_recv; + pj_timestamp start_time; +}; + +static void on_read_complete(pj_ioqueue_key_t *key, pj_ssize_t bytes_read) +{ + struct server *server = pj_ioqueue_get_user_data(key); + pj_status_t rc; + + if (server->sock_type == PJ_SOCK_DGRAM) { + if (bytes_read > 0) { + /* Send data back to sender. */ + rc = pj_ioqueue_sendto( server->ioqueue, server->key, + server->buf, bytes_read, 0, + &server->addr, server->addrlen); + if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { + app_perror("...sendto() error", rc); + } + } else { + PJ_LOG(3,("", "...read error (bytes_read=%d)", bytes_read)); + } + + /* Start next receive. */ + rc = pj_ioqueue_recvfrom( server->ioqueue, server->key, + server->buf, server->bufsize, 0, + &server->addr, &server->addrlen); + if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { + app_perror("...recvfrom() error", rc); + } + + } + else if (server->sock_type == PJ_SOCK_STREAM) { + if (bytes_read > 0) { + /* Send data back to sender. */ + rc = pj_ioqueue_send( server->ioqueue, server->key, + server->buf, bytes_read, 0); + if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { + app_perror("...send() error", rc); + bytes_read = 0; + } + } + + if (bytes_read <= 0) { + PJ_LOG(3,("", "...tcp closed")); + pj_ioqueue_unregister( server->ioqueue, server->key ); + pj_sock_close( server->sock ); + pj_pool_release( server->pool ); + return; + } + + /* Start next receive. */ + rc = pj_ioqueue_recv( server->ioqueue, server->key, + server->buf, server->bufsize, 0); + if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { + app_perror("...recv() error", rc); + } + } + + /* Add counter. */ + if (bytes_read > 0) { + if (server->bytes_recv == 0) { + pj_get_timestamp(&server->start_time); + server->bytes_recv += bytes_read; + } else { + enum { USECS_IN_SECOND = 1000000 }; + pj_timestamp now; + pj_uint32_t usec_elapsed; + + server->bytes_recv += bytes_read; + + pj_get_timestamp(&now); + usec_elapsed = pj_elapsed_usec(&server->start_time, &now); + if (usec_elapsed > USECS_IN_SECOND) { + if (usec_elapsed < 2 * USECS_IN_SECOND) { + pj_highprec_t bw; + pj_uint32_t bw32; + const char *type_name; + + /* bandwidth(bw) = server->bytes_recv * USECS/elapsed */ + bw = server->bytes_recv; + pj_highprec_mul(bw, USECS_IN_SECOND); + pj_highprec_div(bw, usec_elapsed); + + bw32 = (pj_uint32_t) bw; + + if (server->sock_type==PJ_SOCK_STREAM) + type_name = "tcp"; + else if (server->sock_type==PJ_SOCK_DGRAM) + type_name = "udp"; + else + type_name = "???"; + + PJ_LOG(3,("", + "...[%s:%d (%d threads)] Current bandwidth=%u KBps", + type_name, + ECHO_SERVER_START_PORT+server->thread_count, + server->thread_count, + bw32/1024)); + } + server->start_time = now; + server->bytes_recv = 0; + } + } + } +} + +static void on_accept_complete( pj_ioqueue_key_t *key, pj_sock_t sock, + int status) +{ + struct server *server_server = pj_ioqueue_get_user_data(key); + pj_status_t rc; + + PJ_UNUSED_ARG(sock); + + if (status == 0) { + pj_pool_t *pool; + struct server *new_server; + + pool = pj_pool_create(mem, NULL, 4000, 4000, NULL); + new_server = pj_pool_zalloc(pool, sizeof(struct server)); + + new_server->pool = pool; + new_server->ioqueue = server_server->ioqueue; + new_server->sock_type = server_server->sock_type; + new_server->thread_count = server_server->thread_count; + new_server->sock = server_server->client_sock; + new_server->bufsize = 4096; + new_server->buf = pj_pool_alloc(pool, new_server->bufsize); + new_server->cb = server_server->cb; + + rc = pj_ioqueue_register_sock( new_server->pool, new_server->ioqueue, + new_server->sock, new_server, + &server_server->cb, &new_server->key); + if (rc != PJ_SUCCESS) { + app_perror("...registering new tcp sock", rc); + pj_sock_close(new_server->sock); + pj_pool_release(pool); + thread_quit_flag = 1; + return; + } + + rc = pj_ioqueue_recv( new_server->ioqueue, new_server->key, + new_server->buf, new_server->bufsize, 0); + if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { + app_perror("...recv() error", rc); + pj_sock_close(new_server->sock); + pj_pool_release(pool); + thread_quit_flag = 1; + return; + } + } + + rc = pj_ioqueue_accept( server_server->ioqueue, server_server->key, + &server_server->client_sock, + NULL, NULL, NULL); + if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { + app_perror("...accept() error", rc); + thread_quit_flag = 1; + } +} + +static int thread_proc(void *arg) +{ + pj_ioqueue_t *ioqueue = arg; + + while (!thread_quit_flag) { + pj_time_val timeout; + int count; + + timeout.sec = 0; timeout.msec = 50; + count = pj_ioqueue_poll( ioqueue, &timeout ); + if (count > 0) { + count = 0; + } + } + + return 0; +} + +static int start_echo_server( int sock_type, int port, int thread_count ) +{ + pj_pool_t *pool; + struct server *server; + int i; + pj_status_t rc; + + + pool = pj_pool_create(mem, NULL, 4000, 4000, NULL); + if (!pool) + return -10; + + server = pj_pool_zalloc(pool, sizeof(struct server)); + + server->sock_type = sock_type; + server->thread_count = thread_count; + server->cb.on_read_complete = &on_read_complete; + server->cb.on_accept_complete = &on_accept_complete; + + /* create ioqueue */ + rc = pj_ioqueue_create( pool, 32, thread_count, &server->ioqueue); + if (rc != PJ_SUCCESS) { + app_perror("...error creating ioqueue", rc); + return -20; + } + + /* create and register socket to ioqueue. */ + rc = app_socket(PJ_AF_INET, sock_type, 0, port, &server->sock); + if (rc != PJ_SUCCESS) { + app_perror("...error initializing socket", rc); + return -30; + } + + rc = pj_ioqueue_register_sock( pool, server->ioqueue, + server->sock, + server, &server->cb, + &server->key); + if (rc != PJ_SUCCESS) { + app_perror("...error registering socket to ioqueue", rc); + return -40; + } + + /* create receive buffer. */ + server->bufsize = 4096; + server->buf = pj_pool_alloc(pool, server->bufsize); + + if (sock_type == PJ_SOCK_DGRAM) { + server->addrlen = sizeof(server->addr); + rc = pj_ioqueue_recvfrom( server->ioqueue, server->key, + server->buf, server->bufsize, + 0, + &server->addr, &server->addrlen); + if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { + app_perror("...read error", rc); + return -50; + } + } else { + rc = pj_ioqueue_accept( server->ioqueue, server->key, + &server->client_sock, NULL, NULL, NULL ); + if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { + app_perror("...accept() error", rc); + return -60; + } + } + + /* create threads. */ + + for (i=0; iioqueue, + PJ_THREAD_DEFAULT_STACK_SIZE, 0, &thread); + if (rc != PJ_SUCCESS) { + app_perror("...unable to create thread", rc); + return -70; + } + } + + /* Done. */ + return PJ_SUCCESS; +} + +int echo_server(void) +{ + enum { MAX_THREADS = 4 }; + int sock_types[2]; + int i, j, rc; + + sock_types[0] = PJ_SOCK_DGRAM; + sock_types[1] = PJ_SOCK_STREAM; + + for (i=0; i<2; ++i) { + for (j=0; j -#include -#include -#include -#include - -#if INCLUDE_ERRNO_TEST - -#define THIS_FILE "errno" - -#if defined(PJ_WIN32) && PJ_WIN32 != 0 -# include -#endif - -#if defined(PJ_HAS_ERRNO_H) && PJ_HAS_ERRNO_H != 0 -# include -#endif - -static void trim_newlines(char *s) -{ - while (*s) { - if (*s == '\r' || *s == '\n') - *s = ' '; - ++s; - } -} - -int my_strncasecmp(const char *s1, const char *s2, int max_len) -{ - while (*s1 && *s2 && max_len > 0) { - if (pj_tolower(*s1) != pj_tolower(*s2)) - return -1; - ++s1; - ++s2; - --max_len; - } - return 0; -} - -const char *my_stristr(const char *whole, const char *part) -{ - int part_len = strlen(part); - while (*whole) { - if (my_strncasecmp(whole, part, part_len) == 0) - return whole; - ++whole; - } - return NULL; -} - -int errno_test(void) -{ - enum { CUT = 6 }; - pj_status_t rc; - char errbuf[256]; - - PJ_LOG(3,(THIS_FILE, "...errno test: check the msg carefully")); - - /* - * Windows platform error. - */ -# ifdef ERROR_INVALID_DATA - rc = PJ_STATUS_FROM_OS(ERROR_INVALID_DATA); - pj_set_os_error(rc); - - /* Whole */ - pj_strerror(rc, errbuf, sizeof(errbuf)); - trim_newlines(errbuf); - PJ_LOG(3,(THIS_FILE, "...msg for rc=ERROR_INVALID_DATA: '%s'", errbuf)); - if (my_stristr(errbuf, "invalid") == NULL) { - PJ_LOG(3, (THIS_FILE, - "...error: expecting \"invalid\" string in the msg")); - return -20; - } - - /* Cut version. */ - pj_strerror(rc, errbuf, CUT); - PJ_LOG(3,(THIS_FILE, "...msg for rc=ERROR_INVALID_DATA (cut): '%s'", errbuf)); -# endif - - /* - * Unix errors - */ -# ifdef EINVAL - rc = PJ_STATUS_FROM_OS(EINVAL); - pj_set_os_error(rc); - - /* Whole */ - pj_strerror(rc, errbuf, sizeof(errbuf)); - trim_newlines(errbuf); - PJ_LOG(3,(THIS_FILE, "...msg for rc=EINVAL: '%s'", errbuf)); - if (my_stristr(errbuf, "invalid") == NULL) { - PJ_LOG(3, (THIS_FILE, - "...error: expecting \"invalid\" string in the msg")); - return -30; - } - - /* Cut */ - pj_strerror(rc, errbuf, CUT); - PJ_LOG(3,(THIS_FILE, "...msg for rc=EINVAL (cut): '%s'", errbuf)); -# endif - - /* - * Windows WSA errors - */ -# ifdef WSAEINVAL - rc = PJ_STATUS_FROM_OS(WSAEINVAL); - pj_set_os_error(rc); - - /* Whole */ - pj_strerror(rc, errbuf, sizeof(errbuf)); - trim_newlines(errbuf); - PJ_LOG(3,(THIS_FILE, "...msg for rc=WSAEINVAL: '%s'", errbuf)); - if (my_stristr(errbuf, "invalid") == NULL) { - PJ_LOG(3, (THIS_FILE, - "...error: expecting \"invalid\" string in the msg")); - return -40; - } - - /* Cut */ - pj_strerror(rc, errbuf, CUT); - PJ_LOG(3,(THIS_FILE, "...msg for rc=WSAEINVAL (cut): '%s'", errbuf)); -# endif - - pj_strerror(PJ_EBUG, errbuf, sizeof(errbuf)); - PJ_LOG(3,(THIS_FILE, "...msg for rc=PJ_EBUG: '%s'", errbuf)); - if (my_stristr(errbuf, "BUG") == NULL) { - PJ_LOG(3, (THIS_FILE, - "...error: expecting \"BUG\" string in the msg")); - return -20; - } - - pj_strerror(PJ_EBUG, errbuf, CUT); - PJ_LOG(3,(THIS_FILE, "...msg for rc=PJ_EBUG, cut at %d chars: '%s'", - CUT, errbuf)); - - return 0; -} - - -#endif /* INCLUDE_ERRNO_TEST */ - - +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/errno.c 4 10/14/05 3:05p Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pjlib-test/errno.c $ + * + * 4 10/14/05 3:05p Bennylp + * Fixed warning about strlen() on Linux. + * + * 3 14/10/05 11:30 Bennylp + * Verify the error message. + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 10/09/05 9:56p Bennylp + * Created. + * + */ +#include "test.h" +#include +#include +#include +#include +#include + +#if INCLUDE_ERRNO_TEST + +#define THIS_FILE "errno" + +#if defined(PJ_WIN32) && PJ_WIN32 != 0 +# include +#endif + +#if defined(PJ_HAS_ERRNO_H) && PJ_HAS_ERRNO_H != 0 +# include +#endif + +static void trim_newlines(char *s) +{ + while (*s) { + if (*s == '\r' || *s == '\n') + *s = ' '; + ++s; + } +} + +int my_strncasecmp(const char *s1, const char *s2, int max_len) +{ + while (*s1 && *s2 && max_len > 0) { + if (pj_tolower(*s1) != pj_tolower(*s2)) + return -1; + ++s1; + ++s2; + --max_len; + } + return 0; +} + +const char *my_stristr(const char *whole, const char *part) +{ + int part_len = strlen(part); + while (*whole) { + if (my_strncasecmp(whole, part, part_len) == 0) + return whole; + ++whole; + } + return NULL; +} + +int errno_test(void) +{ + enum { CUT = 6 }; + pj_status_t rc; + char errbuf[256]; + + PJ_LOG(3,(THIS_FILE, "...errno test: check the msg carefully")); + + /* + * Windows platform error. + */ +# ifdef ERROR_INVALID_DATA + rc = PJ_STATUS_FROM_OS(ERROR_INVALID_DATA); + pj_set_os_error(rc); + + /* Whole */ + pj_strerror(rc, errbuf, sizeof(errbuf)); + trim_newlines(errbuf); + PJ_LOG(3,(THIS_FILE, "...msg for rc=ERROR_INVALID_DATA: '%s'", errbuf)); + if (my_stristr(errbuf, "invalid") == NULL) { + PJ_LOG(3, (THIS_FILE, + "...error: expecting \"invalid\" string in the msg")); + return -20; + } + + /* Cut version. */ + pj_strerror(rc, errbuf, CUT); + PJ_LOG(3,(THIS_FILE, "...msg for rc=ERROR_INVALID_DATA (cut): '%s'", errbuf)); +# endif + + /* + * Unix errors + */ +# ifdef EINVAL + rc = PJ_STATUS_FROM_OS(EINVAL); + pj_set_os_error(rc); + + /* Whole */ + pj_strerror(rc, errbuf, sizeof(errbuf)); + trim_newlines(errbuf); + PJ_LOG(3,(THIS_FILE, "...msg for rc=EINVAL: '%s'", errbuf)); + if (my_stristr(errbuf, "invalid") == NULL) { + PJ_LOG(3, (THIS_FILE, + "...error: expecting \"invalid\" string in the msg")); + return -30; + } + + /* Cut */ + pj_strerror(rc, errbuf, CUT); + PJ_LOG(3,(THIS_FILE, "...msg for rc=EINVAL (cut): '%s'", errbuf)); +# endif + + /* + * Windows WSA errors + */ +# ifdef WSAEINVAL + rc = PJ_STATUS_FROM_OS(WSAEINVAL); + pj_set_os_error(rc); + + /* Whole */ + pj_strerror(rc, errbuf, sizeof(errbuf)); + trim_newlines(errbuf); + PJ_LOG(3,(THIS_FILE, "...msg for rc=WSAEINVAL: '%s'", errbuf)); + if (my_stristr(errbuf, "invalid") == NULL) { + PJ_LOG(3, (THIS_FILE, + "...error: expecting \"invalid\" string in the msg")); + return -40; + } + + /* Cut */ + pj_strerror(rc, errbuf, CUT); + PJ_LOG(3,(THIS_FILE, "...msg for rc=WSAEINVAL (cut): '%s'", errbuf)); +# endif + + pj_strerror(PJ_EBUG, errbuf, sizeof(errbuf)); + PJ_LOG(3,(THIS_FILE, "...msg for rc=PJ_EBUG: '%s'", errbuf)); + if (my_stristr(errbuf, "BUG") == NULL) { + PJ_LOG(3, (THIS_FILE, + "...error: expecting \"BUG\" string in the msg")); + return -20; + } + + pj_strerror(PJ_EBUG, errbuf, CUT); + PJ_LOG(3,(THIS_FILE, "...msg for rc=PJ_EBUG, cut at %d chars: '%s'", + CUT, errbuf)); + + return 0; +} + + +#endif /* INCLUDE_ERRNO_TEST */ + + diff --git a/pjlib/src/pjlib-test/exception.c b/pjlib/src/pjlib-test/exception.c index 2fe62e6e..4a703607 100644 --- a/pjlib/src/pjlib-test/exception.c +++ b/pjlib/src/pjlib-test/exception.c @@ -1,156 +1,156 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/exception.c 2 10/14/05 12:26a Bennylp $ - */ -#include "test.h" - - -/** - * \page page_pjlib_exception_test Test: Exception Handling - * - * This file provides implementation of \b exception_test(). It tests the - * functionality of the exception handling API. - * - * @note This test use static ID not acquired through proper registration. - * This is not recommended, since it may create ID collissions. - * - * \section exception_test_sec Scope of the Test - * - * Some scenarios tested: - * - no exception situation - * - basic TRY/CATCH - * - multiple exception handlers - * - default handlers - * - * - * This file is pjlib-test/exception.c - * - * \include pjlib-test/exception.c - */ - - -#if INCLUDE_EXCEPTION_TEST - -#include - -#define ID_1 1 -#define ID_2 2 - -static int throw_id_1(void) -{ - PJ_THROW( ID_1 ); - return -1; -} - -static int throw_id_2(void) -{ - PJ_THROW( ID_2 ); - return -1; -} - - -static int test(void) -{ - PJ_USE_EXCEPTION; - int rc = 0; - - /* - * No exception situation. - */ - PJ_TRY { - rc = rc; - } - PJ_CATCH( ID_1 ) { - rc = -2; - } - PJ_DEFAULT { - rc = -3; - } - PJ_END; - - if (rc != 0) - return rc; - - - /* - * Basic TRY/CATCH - */ - PJ_TRY { - rc = throw_id_1(); - - // should not reach here. - rc = -10; - } - PJ_CATCH( ID_1 ) { - if (!rc) rc = 0; - } - PJ_DEFAULT { - if (!rc) rc = -20; - } - PJ_END; - - if (rc != 0) - return rc; - - /* - * Multiple exceptions handlers - */ - PJ_TRY { - rc = throw_id_2(); - // should not reach here. - rc = -25; - } - PJ_CATCH( ID_1 ) { - if (!rc) rc = -30; - } - PJ_CATCH( ID_2 ) { - if (!rc) rc = 0; - } - PJ_DEFAULT { - if (!rc) rc = -40; - } - PJ_END; - - if (rc != 0) - return rc; - - /* - * Test default handler. - */ - PJ_TRY { - rc = throw_id_1(); - // should not reach here - rc = -50; - } - PJ_CATCH( ID_2 ) { - if (!rc) rc = -60; - } - PJ_DEFAULT { - if (!rc) rc = 0; - } - PJ_END; - - if (rc != 0) - return rc; - - return 0; -} - -int exception_test(void) -{ - int i, rc; - enum { LOOP = 10 }; - - for (i=0; ipjlib-test/exception.c + * + * \include pjlib-test/exception.c + */ + + +#if INCLUDE_EXCEPTION_TEST + +#include + +#define ID_1 1 +#define ID_2 2 + +static int throw_id_1(void) +{ + PJ_THROW( ID_1 ); + return -1; +} + +static int throw_id_2(void) +{ + PJ_THROW( ID_2 ); + return -1; +} + + +static int test(void) +{ + PJ_USE_EXCEPTION; + int rc = 0; + + /* + * No exception situation. + */ + PJ_TRY { + rc = rc; + } + PJ_CATCH( ID_1 ) { + rc = -2; + } + PJ_DEFAULT { + rc = -3; + } + PJ_END; + + if (rc != 0) + return rc; + + + /* + * Basic TRY/CATCH + */ + PJ_TRY { + rc = throw_id_1(); + + // should not reach here. + rc = -10; + } + PJ_CATCH( ID_1 ) { + if (!rc) rc = 0; + } + PJ_DEFAULT { + if (!rc) rc = -20; + } + PJ_END; + + if (rc != 0) + return rc; + + /* + * Multiple exceptions handlers + */ + PJ_TRY { + rc = throw_id_2(); + // should not reach here. + rc = -25; + } + PJ_CATCH( ID_1 ) { + if (!rc) rc = -30; + } + PJ_CATCH( ID_2 ) { + if (!rc) rc = 0; + } + PJ_DEFAULT { + if (!rc) rc = -40; + } + PJ_END; + + if (rc != 0) + return rc; + + /* + * Test default handler. + */ + PJ_TRY { + rc = throw_id_1(); + // should not reach here + rc = -50; + } + PJ_CATCH( ID_2 ) { + if (!rc) rc = -60; + } + PJ_DEFAULT { + if (!rc) rc = 0; + } + PJ_END; + + if (rc != 0) + return rc; + + return 0; +} + +int exception_test(void) +{ + int i, rc; + enum { LOOP = 10 }; + + for (i=0; i - -int fifobuf_test() -{ - enum { SIZE = 1024, MAX_ENTRIES = 128, - MIN_SIZE = 4, MAX_SIZE = 64, - LOOP=10000 }; - pj_pool_t *pool; - pj_fifobuf_t fifo; - unsigned available = SIZE; - void *entries[MAX_ENTRIES]; - void *buffer; - int i; - - pool = pj_pool_create(mem, NULL, SIZE+256, 0, NULL); - if (!pool) - return -10; - - buffer = pj_pool_alloc(pool, SIZE); - if (!buffer) - return -20; - - pj_fifobuf_init (&fifo, buffer, SIZE); - - // Test 1 - for (i=0; i=MIN_SIZE+4 && count < MAX_ENTRIES;) { - int size = MIN_SIZE+(pj_rand() % MAX_SIZE); - entries[count] = pj_fifobuf_alloc (&fifo, size); - if (entries[count]) { - available -= (size+4); - ++count; - } - } - for (j=0; j + +int fifobuf_test() +{ + enum { SIZE = 1024, MAX_ENTRIES = 128, + MIN_SIZE = 4, MAX_SIZE = 64, + LOOP=10000 }; + pj_pool_t *pool; + pj_fifobuf_t fifo; + unsigned available = SIZE; + void *entries[MAX_ENTRIES]; + void *buffer; + int i; + + pool = pj_pool_create(mem, NULL, SIZE+256, 0, NULL); + if (!pool) + return -10; + + buffer = pj_pool_alloc(pool, SIZE); + if (!buffer) + return -20; + + pj_fifobuf_init (&fifo, buffer, SIZE); + + // Test 1 + for (i=0; i=MIN_SIZE+4 && count < MAX_ENTRIES;) { + int size = MIN_SIZE+(pj_rand() % MAX_SIZE); + entries[count] = pj_fifobuf_alloc (&fifo, size); + if (entries[count]) { + available -= (size+4); + ++count; + } + } + for (j=0; j -#include - -/** - * \page page_pjlib_ioqueue_perf_test Test: I/O Queue Performance - * - * Test the performance of the I/O queue, using typical producer - * consumer test. The test should examine the effect of using multiple - * threads on the performance. - * - * This file is pjlib-test/ioq_perf.c - * - * \include pjlib-test/ioq_perf.c - */ - -#if INCLUDE_IOQUEUE_PERF_TEST - -#ifdef _MSC_VER -# pragma warning ( disable: 4204) // non-constant aggregate initializer -#endif - -#define THIS_FILE "ioq_perf" -//#define TRACE_(expr) PJ_LOG(3,expr) -#define TRACE_(expr) - - -static pj_bool_t thread_quit_flag; -static pj_status_t last_error; -static unsigned last_error_counter; - -/* Descriptor for each producer/consumer pair. */ -typedef struct test_item -{ - pj_sock_t server_fd, - client_fd; - pj_ioqueue_t *ioqueue; - pj_ioqueue_key_t *server_key, - *client_key; - pj_size_t buffer_size; - char *outgoing_buffer; - char *incoming_buffer; - pj_size_t bytes_sent, - bytes_recv; -} test_item; - -/* Callback when data has been read. - * Increment item->bytes_recv and ready to read the next data. - */ -static void on_read_complete(pj_ioqueue_key_t *key, pj_ssize_t bytes_read) -{ - test_item *item = pj_ioqueue_get_user_data(key); - pj_status_t rc; - - //TRACE_((THIS_FILE, " read complete, bytes_read=%d", bytes_read)); - - if (thread_quit_flag) - return; - - if (bytes_read < 0) { - pj_status_t rc = -bytes_read; - char errmsg[128]; - - if (rc != last_error) { - last_error = rc; - pj_strerror(rc, errmsg, sizeof(errmsg)); - PJ_LOG(3,(THIS_FILE, "...error: read error, bytes_read=%d (%s)", - bytes_read, errmsg)); - PJ_LOG(3,(THIS_FILE, - ".....additional info: total read=%u, total written=%u", - item->bytes_recv, item->bytes_sent)); - } else { - last_error_counter++; - } - bytes_read = 0; - - } else if (bytes_read == 0) { - PJ_LOG(3,(THIS_FILE, "...socket has closed!")); - } - - item->bytes_recv += bytes_read; - - /* To assure that the test quits, even if main thread - * doesn't have time to run. - */ - if (item->bytes_recv > item->buffer_size * 10000) - thread_quit_flag = 1; - - rc = pj_ioqueue_recv( item->ioqueue, item->server_key, - item->incoming_buffer, item->buffer_size, 0 ); - - if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { - if (rc != last_error) { - last_error = rc; - app_perror("...error: read error", rc); - } else { - last_error_counter++; - } - } -} - -/* Callback when data has been written. - * Increment item->bytes_sent and write the next data. - */ -static void on_write_complete(pj_ioqueue_key_t *key, pj_ssize_t bytes_sent) -{ - test_item *item = pj_ioqueue_get_user_data(key); - - //TRACE_((THIS_FILE, " write complete: sent = %d", bytes_sent)); - - if (thread_quit_flag) - return; - - item->bytes_sent += bytes_sent; - - if (bytes_sent <= 0) { - PJ_LOG(3,(THIS_FILE, "...error: sending stopped. bytes_sent=%d", - bytes_sent)); - } - else { - pj_status_t rc; - - rc = pj_ioqueue_write(item->ioqueue, item->client_key, - item->outgoing_buffer, item->buffer_size); - if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { - app_perror("...error: write error", rc); - } - } -} - -/* The worker thread. */ -static int worker_thread(void *arg) -{ - pj_ioqueue_t *ioqueue = arg; - const pj_time_val timeout = {0, 100}; - int rc; - - while (!thread_quit_flag) { - rc = pj_ioqueue_poll(ioqueue, &timeout); - //TRACE_((THIS_FILE, " thread: poll returned rc=%d", rc)); - if (rc < 0) { - app_perror("...error in pj_ioqueue_poll()", pj_get_netos_error()); - return -1; - } - } - return 0; -} - -/* Calculate the bandwidth for the specific test configuration. - * The test is simple: - * - create sockpair_cnt number of producer-consumer socket pair. - * - create thread_cnt number of worker threads. - * - each producer will send buffer_size bytes data as fast and - * as soon as it can. - * - each consumer will read buffer_size bytes of data as fast - * as it could. - * - measure the total bytes received by all consumers during a - * period of time. - */ -static int perform_test(int sock_type, const char *type_name, - unsigned thread_cnt, unsigned sockpair_cnt, - pj_size_t buffer_size, - pj_size_t *p_bandwidth) -{ - enum { MSEC_DURATION = 5000 }; - pj_pool_t *pool; - test_item *items; - pj_thread_t **thread; - pj_ioqueue_t *ioqueue; - pj_status_t rc; - pj_ioqueue_callback ioqueue_callback; - pj_uint32_t total_elapsed_usec, total_received; - pj_highprec_t bandwidth; - pj_timestamp start, stop; - unsigned i; - - TRACE_((THIS_FILE, " starting test..")); - - ioqueue_callback.on_read_complete = &on_read_complete; - ioqueue_callback.on_write_complete = &on_write_complete; - - thread_quit_flag = 0; - - pool = pj_pool_create(mem, NULL, 4096, 4096, NULL); - if (!pool) - return -10; - - items = pj_pool_alloc(pool, sockpair_cnt*sizeof(test_item)); - thread = pj_pool_alloc(pool, thread_cnt*sizeof(pj_thread_t*)); - - TRACE_((THIS_FILE, " creating ioqueue..")); - rc = pj_ioqueue_create(pool, sockpair_cnt*2, thread_cnt, &ioqueue); - if (rc != PJ_SUCCESS) { - app_perror("...error: unable to create ioqueue", rc); - return -15; - } - - /* Initialize each producer-consumer pair. */ - for (i=0; i best_bandwidth) - best_bandwidth = bandwidth, best_index = i; - - /* Give it a rest before next test. */ - pj_thread_sleep(500); - } - - PJ_LOG(3,(THIS_FILE, - " Best: Type=%s Threads=%d, Skt.Pairs=%d, Bandwidth=%u KB/s", - test_param[best_index].type_name, - test_param[best_index].thread_cnt, - test_param[best_index].sockpair_cnt, - best_bandwidth)); - PJ_LOG(3,(THIS_FILE, " (Note: packet size=%d, total errors=%u)", - BUF_SIZE, last_error_counter)); - return 0; -} - -#else -/* To prevent warning about "translation unit is empty" - * when this test is disabled. - */ -int dummy_uiq_perf_test; -#endif /* INCLUDE_IOQUEUE_PERF_TEST */ - - +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/ioq_perf.c 4 10/29/05 11:51a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pjlib-test/ioq_perf.c $ + * + * 4 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 3 14/10/05 11:31 Bennylp + * More generalized test method, works for UDP too. + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 10/11/05 3:52p Bennylp + * Created. + * + */ +#include "test.h" +#include +#include + +/** + * \page page_pjlib_ioqueue_perf_test Test: I/O Queue Performance + * + * Test the performance of the I/O queue, using typical producer + * consumer test. The test should examine the effect of using multiple + * threads on the performance. + * + * This file is pjlib-test/ioq_perf.c + * + * \include pjlib-test/ioq_perf.c + */ + +#if INCLUDE_IOQUEUE_PERF_TEST + +#ifdef _MSC_VER +# pragma warning ( disable: 4204) // non-constant aggregate initializer +#endif + +#define THIS_FILE "ioq_perf" +//#define TRACE_(expr) PJ_LOG(3,expr) +#define TRACE_(expr) + + +static pj_bool_t thread_quit_flag; +static pj_status_t last_error; +static unsigned last_error_counter; + +/* Descriptor for each producer/consumer pair. */ +typedef struct test_item +{ + pj_sock_t server_fd, + client_fd; + pj_ioqueue_t *ioqueue; + pj_ioqueue_key_t *server_key, + *client_key; + pj_size_t buffer_size; + char *outgoing_buffer; + char *incoming_buffer; + pj_size_t bytes_sent, + bytes_recv; +} test_item; + +/* Callback when data has been read. + * Increment item->bytes_recv and ready to read the next data. + */ +static void on_read_complete(pj_ioqueue_key_t *key, pj_ssize_t bytes_read) +{ + test_item *item = pj_ioqueue_get_user_data(key); + pj_status_t rc; + + //TRACE_((THIS_FILE, " read complete, bytes_read=%d", bytes_read)); + + if (thread_quit_flag) + return; + + if (bytes_read < 0) { + pj_status_t rc = -bytes_read; + char errmsg[128]; + + if (rc != last_error) { + last_error = rc; + pj_strerror(rc, errmsg, sizeof(errmsg)); + PJ_LOG(3,(THIS_FILE, "...error: read error, bytes_read=%d (%s)", + bytes_read, errmsg)); + PJ_LOG(3,(THIS_FILE, + ".....additional info: total read=%u, total written=%u", + item->bytes_recv, item->bytes_sent)); + } else { + last_error_counter++; + } + bytes_read = 0; + + } else if (bytes_read == 0) { + PJ_LOG(3,(THIS_FILE, "...socket has closed!")); + } + + item->bytes_recv += bytes_read; + + /* To assure that the test quits, even if main thread + * doesn't have time to run. + */ + if (item->bytes_recv > item->buffer_size * 10000) + thread_quit_flag = 1; + + rc = pj_ioqueue_recv( item->ioqueue, item->server_key, + item->incoming_buffer, item->buffer_size, 0 ); + + if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { + if (rc != last_error) { + last_error = rc; + app_perror("...error: read error", rc); + } else { + last_error_counter++; + } + } +} + +/* Callback when data has been written. + * Increment item->bytes_sent and write the next data. + */ +static void on_write_complete(pj_ioqueue_key_t *key, pj_ssize_t bytes_sent) +{ + test_item *item = pj_ioqueue_get_user_data(key); + + //TRACE_((THIS_FILE, " write complete: sent = %d", bytes_sent)); + + if (thread_quit_flag) + return; + + item->bytes_sent += bytes_sent; + + if (bytes_sent <= 0) { + PJ_LOG(3,(THIS_FILE, "...error: sending stopped. bytes_sent=%d", + bytes_sent)); + } + else { + pj_status_t rc; + + rc = pj_ioqueue_write(item->ioqueue, item->client_key, + item->outgoing_buffer, item->buffer_size); + if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { + app_perror("...error: write error", rc); + } + } +} + +/* The worker thread. */ +static int worker_thread(void *arg) +{ + pj_ioqueue_t *ioqueue = arg; + const pj_time_val timeout = {0, 100}; + int rc; + + while (!thread_quit_flag) { + rc = pj_ioqueue_poll(ioqueue, &timeout); + //TRACE_((THIS_FILE, " thread: poll returned rc=%d", rc)); + if (rc < 0) { + app_perror("...error in pj_ioqueue_poll()", pj_get_netos_error()); + return -1; + } + } + return 0; +} + +/* Calculate the bandwidth for the specific test configuration. + * The test is simple: + * - create sockpair_cnt number of producer-consumer socket pair. + * - create thread_cnt number of worker threads. + * - each producer will send buffer_size bytes data as fast and + * as soon as it can. + * - each consumer will read buffer_size bytes of data as fast + * as it could. + * - measure the total bytes received by all consumers during a + * period of time. + */ +static int perform_test(int sock_type, const char *type_name, + unsigned thread_cnt, unsigned sockpair_cnt, + pj_size_t buffer_size, + pj_size_t *p_bandwidth) +{ + enum { MSEC_DURATION = 5000 }; + pj_pool_t *pool; + test_item *items; + pj_thread_t **thread; + pj_ioqueue_t *ioqueue; + pj_status_t rc; + pj_ioqueue_callback ioqueue_callback; + pj_uint32_t total_elapsed_usec, total_received; + pj_highprec_t bandwidth; + pj_timestamp start, stop; + unsigned i; + + TRACE_((THIS_FILE, " starting test..")); + + ioqueue_callback.on_read_complete = &on_read_complete; + ioqueue_callback.on_write_complete = &on_write_complete; + + thread_quit_flag = 0; + + pool = pj_pool_create(mem, NULL, 4096, 4096, NULL); + if (!pool) + return -10; + + items = pj_pool_alloc(pool, sockpair_cnt*sizeof(test_item)); + thread = pj_pool_alloc(pool, thread_cnt*sizeof(pj_thread_t*)); + + TRACE_((THIS_FILE, " creating ioqueue..")); + rc = pj_ioqueue_create(pool, sockpair_cnt*2, thread_cnt, &ioqueue); + if (rc != PJ_SUCCESS) { + app_perror("...error: unable to create ioqueue", rc); + return -15; + } + + /* Initialize each producer-consumer pair. */ + for (i=0; i best_bandwidth) + best_bandwidth = bandwidth, best_index = i; + + /* Give it a rest before next test. */ + pj_thread_sleep(500); + } + + PJ_LOG(3,(THIS_FILE, + " Best: Type=%s Threads=%d, Skt.Pairs=%d, Bandwidth=%u KB/s", + test_param[best_index].type_name, + test_param[best_index].thread_cnt, + test_param[best_index].sockpair_cnt, + best_bandwidth)); + PJ_LOG(3,(THIS_FILE, " (Note: packet size=%d, total errors=%u)", + BUF_SIZE, last_error_counter)); + return 0; +} + +#else +/* To prevent warning about "translation unit is empty" + * when this test is disabled. + */ +int dummy_uiq_perf_test; +#endif /* INCLUDE_IOQUEUE_PERF_TEST */ + + diff --git a/pjlib/src/pjlib-test/ioq_tcp.c b/pjlib/src/pjlib-test/ioq_tcp.c index 434c25ae..99656643 100644 --- a/pjlib/src/pjlib-test/ioq_tcp.c +++ b/pjlib/src/pjlib-test/ioq_tcp.c @@ -1,474 +1,474 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/ioq_tcp.c 4 10/29/05 10:23p Bennylp $ - */ -/* - * $Log: /pjproject-0.3/pjlib/src/pjlib-test/ioq_tcp.c $ - * - * 4 10/29/05 10:23p Bennylp - * Fixed no-memory exception. - * - * 3 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - */ -#include "test.h" - -/** - * \page page_pjlib_ioqueue_tcp_test Test: I/O Queue (TCP) - * - * This file provides implementation to test the - * functionality of the I/O queue when TCP socket is used. - * - * - * This file is pjlib-test/ioq_tcp.c - * - * \include pjlib-test/ioq_tcp.c - */ - - -#if INCLUDE_TCP_IOQUEUE_TEST - -#include - -#if PJ_HAS_TCP - -#define THIS_FILE "test_tcp" -#define PORT 50000 -#define NON_EXISTANT_PORT 50123 -#define LOOP 100 -#define BUF_MIN_SIZE 32 -#define BUF_MAX_SIZE 2048 -#define SOCK_INACTIVE_MIN (4-2) -#define SOCK_INACTIVE_MAX (PJ_IOQUEUE_MAX_HANDLES - 2) -#define POOL_SIZE (2*BUF_MAX_SIZE + SOCK_INACTIVE_MAX*128 + 2048) - -static pj_ssize_t callback_read_size, - callback_write_size, - callback_accept_status, - callback_connect_status; -static pj_ioqueue_key_t*callback_read_key, - *callback_write_key, - *callback_accept_key, - *callback_connect_key; - -static void on_ioqueue_read(pj_ioqueue_key_t *key, pj_ssize_t bytes_read) -{ - callback_read_key = key; - callback_read_size = bytes_read; -} - -static void on_ioqueue_write(pj_ioqueue_key_t *key, pj_ssize_t bytes_written) -{ - callback_write_key = key; - callback_write_size = bytes_written; -} - -static void on_ioqueue_accept(pj_ioqueue_key_t *key, pj_sock_t sock, - int status) -{ - PJ_UNUSED_ARG(sock); - - callback_accept_key = key; - callback_accept_status = status; -} - -static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status) -{ - callback_connect_key = key; - callback_connect_status = status; -} - -static pj_ioqueue_callback test_cb = -{ - &on_ioqueue_read, - &on_ioqueue_write, - &on_ioqueue_accept, - &on_ioqueue_connect, -}; - -static int send_recv_test(pj_ioqueue_t *ioque, - pj_ioqueue_key_t *skey, - pj_ioqueue_key_t *ckey, - void *send_buf, - void *recv_buf, - pj_ssize_t bufsize, - pj_timestamp *t_elapsed) -{ - int rc; - pj_ssize_t bytes; - pj_timestamp t1, t2; - int pending_op = 0; - - // Start reading on the server side. - rc = pj_ioqueue_read(ioque, skey, recv_buf, bufsize); - if (rc != 0 && rc != PJ_EPENDING) { - return -100; - } - - ++pending_op; - - // Randomize send buffer. - pj_create_random_string((char*)send_buf, bufsize); - - // Starts send on the client side. - bytes = pj_ioqueue_write(ioque, ckey, send_buf, bufsize); - if (bytes != bufsize && bytes != PJ_EPENDING) { - return -120; - } - if (bytes == PJ_EPENDING) { - ++pending_op; - } - - // Begin time. - pj_get_timestamp(&t1); - - // Reset indicators - callback_read_size = callback_write_size = 0; - callback_read_key = callback_write_key = NULL; - - // Poll the queue until we've got completion event in the server side. - rc = 0; - while (pending_op > 0) { - rc = pj_ioqueue_poll(ioque, NULL); - if (rc > 0) { - if (callback_read_size) { - if (callback_read_size != bufsize) { - return -160; - } - if (callback_read_key != skey) - return -161; - } - if (callback_write_size) { - if (callback_write_key != ckey) - return -162; - } - pending_op -= rc; - } - if (rc < 0) { - return -170; - } - } - - // End time. - pj_get_timestamp(&t2); - t_elapsed->u32.lo += (t2.u32.lo - t1.u32.lo); - - if (rc < 0) { - return -150; - } - - // Compare recv buffer with send buffer. - if (pj_memcmp(send_buf, recv_buf, bufsize) != 0) { - return -180; - } - - // Success - return 0; -} - - -/* - * Compliance test for success scenario. - */ -static int compliance_test_0(void) -{ - pj_sock_t ssock=-1, csock0=-1, csock1=-1; - pj_sockaddr_in addr, client_addr, rmt_addr; - int client_addr_len; - pj_pool_t *pool = NULL; - char *send_buf, *recv_buf; - pj_ioqueue_t *ioque = NULL; - pj_ioqueue_key_t *skey, *ckey0, *ckey1; - int bufsize = BUF_MIN_SIZE; - pj_ssize_t status = -1; - int pending_op = 0; - pj_timestamp t_elapsed; - pj_str_t s; - pj_status_t rc; - - // Create pool. - pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL); - - // Allocate buffers for send and receive. - send_buf = (char*)pj_pool_alloc(pool, bufsize); - recv_buf = (char*)pj_pool_alloc(pool, bufsize); - - // Create server socket and client socket for connecting - rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &ssock); - if (rc != PJ_SUCCESS) { - app_perror("...error creating socket", rc); - status=-1; goto on_error; - } - - rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &csock1); - if (rc != PJ_SUCCESS) { - app_perror("...error creating socket", rc); - status=-1; goto on_error; - } - - // Bind server socket. - memset(&addr, 0, sizeof(addr)); - addr.sin_family = PJ_AF_INET; - addr.sin_port = pj_htons(PORT); - if (pj_sock_bind(ssock, &addr, sizeof(addr))) { - app_perror("...bind error", rc); - status=-10; goto on_error; - } - - // Create I/O Queue. - rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, 0, &ioque); - if (rc != PJ_SUCCESS) { - app_perror("...ERROR in pj_ioqueue_create()", rc); - status=-20; goto on_error; - } - - // Register server socket and client socket. - rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, &test_cb, &skey); - if (rc == PJ_SUCCESS) - rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL, &test_cb, - &ckey1); - else - ckey1 = NULL; - if (rc != PJ_SUCCESS) { - app_perror("...ERROR in pj_ioqueue_register_sock()", rc); - status=-23; goto on_error; - } - - // Server socket listen(). - if (pj_sock_listen(ssock, 5)) { - app_perror("...ERROR in pj_sock_listen()", rc); - status=-25; goto on_error; - } - - // Server socket accept() - client_addr_len = sizeof(pj_sockaddr_in); - status = pj_ioqueue_accept(ioque, skey, &csock0, &client_addr, &rmt_addr, &client_addr_len); - if (status != PJ_EPENDING) { - app_perror("...ERROR in pj_ioqueue_accept()", rc); - status=-30; goto on_error; - } - if (status==PJ_EPENDING) { - ++pending_op; - } - - // Initialize remote address. - memset(&addr, 0, sizeof(addr)); - addr.sin_family = PJ_AF_INET; - addr.sin_port = pj_htons(PORT); - addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1")); - - // Client socket connect() - status = pj_ioqueue_connect(ioque, ckey1, &addr, sizeof(addr)); - if (status!=PJ_SUCCESS && status != PJ_EPENDING) { - app_perror("...ERROR in pj_ioqueue_connect()", rc); - status=-40; goto on_error; - } - if (status==PJ_EPENDING) { - ++pending_op; - } - - // Poll until connected - callback_read_size = callback_write_size = 0; - callback_accept_status = callback_connect_status = -2; - - callback_read_key = callback_write_key = - callback_accept_key = callback_connect_key = NULL; - - while (pending_op) { - pj_time_val timeout = {1, 0}; - - status=pj_ioqueue_poll(ioque, &timeout); - if (status > 0) { - if (callback_accept_status != -2) { - if (callback_accept_status != 0) { - status=-41; goto on_error; - } - if (callback_accept_key != skey) { - status=-41; goto on_error; - } - } - - if (callback_connect_status != -2) { - if (callback_connect_status != 0) { - status=-50; goto on_error; - } - if (callback_connect_key != ckey1) { - status=-51; goto on_error; - } - } - - pending_op -= status; - - if (pending_op == 0) { - status = 0; - } - } - } - - // Check accepted socket. - if (csock0 == PJ_INVALID_SOCKET) { - status = -69; - app_perror("...accept() error", pj_get_os_error()); - goto on_error; - } - - // Register newly accepted socket. - rc = pj_ioqueue_register_sock(pool, ioque, csock0, NULL, - &test_cb, &ckey0); - if (rc != PJ_SUCCESS) { - app_perror("...ERROR in pj_ioqueue_register_sock", rc); - status = -70; - goto on_error; - } - - // Test send and receive. - t_elapsed.u32.lo = 0; - status = send_recv_test(ioque, ckey0, ckey1, send_buf, recv_buf, bufsize, &t_elapsed); - if (status != 0) { - goto on_error; - } - - // Success - status = 0; - -on_error: - if (ssock != PJ_INVALID_SOCKET) - pj_sock_close(ssock); - if (csock1 != PJ_INVALID_SOCKET) - pj_sock_close(csock1); - if (csock0 != PJ_INVALID_SOCKET) - pj_sock_close(csock0); - if (ioque != NULL) - pj_ioqueue_destroy(ioque); - pj_pool_release(pool); - return status; - -} - -/* - * Compliance test for failed scenario. - * In this case, the client connects to a non-existant service. - */ -static int compliance_test_1(void) -{ - pj_sock_t csock1=-1; - pj_sockaddr_in addr; - pj_pool_t *pool = NULL; - pj_ioqueue_t *ioque = NULL; - pj_ioqueue_key_t *ckey1; - pj_ssize_t status = -1; - int pending_op = 0; - pj_str_t s; - pj_status_t rc; - - // Create pool. - pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL); - - // Create I/O Queue. - rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, 0, &ioque); - if (!ioque) { - status=-20; goto on_error; - } - - // Create client socket - rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &csock1); - if (rc != PJ_SUCCESS) { - app_perror("...ERROR in pj_sock_socket()", rc); - status=-1; goto on_error; - } - - // Register client socket. - rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL, - &test_cb, &ckey1); - if (rc != PJ_SUCCESS) { - app_perror("...ERROR in pj_ioqueue_register_sock()", rc); - status=-23; goto on_error; - } - - // Initialize remote address. - memset(&addr, 0, sizeof(addr)); - addr.sin_family = PJ_AF_INET; - addr.sin_port = pj_htons(NON_EXISTANT_PORT); - addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1")); - - // Client socket connect() - status = pj_ioqueue_connect(ioque, ckey1, &addr, sizeof(addr)); - if (status==PJ_SUCCESS) { - // unexpectedly success! - status = -30; - goto on_error; - } - if (status != PJ_EPENDING) { - // success - } else { - ++pending_op; - } - - callback_connect_status = -2; - callback_connect_key = NULL; - - // Poll until we've got result - while (pending_op) { - pj_time_val timeout = {1, 0}; - - status=pj_ioqueue_poll(ioque, &timeout); - if (status > 0) { - if (callback_connect_key==ckey1) { - if (callback_connect_status == 0) { - // unexpectedly connected! - status = -50; - goto on_error; - } - } - - pending_op -= status; - if (pending_op == 0) { - status = 0; - } - } - } - - // Success - status = 0; - -on_error: - if (csock1 != PJ_INVALID_SOCKET) - pj_sock_close(csock1); - if (ioque != NULL) - pj_ioqueue_destroy(ioque); - pj_pool_release(pool); - return status; -} - -int tcp_ioqueue_test() -{ - int status; - - PJ_LOG(3, (THIS_FILE, "..compliance test 0 (success scenario)")); - if ((status=compliance_test_0()) != 0) { - PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status)); - return status; - } - PJ_LOG(3, (THIS_FILE, "..compliance test 1 (failed scenario)")); - if ((status=compliance_test_1()) != 0) { - PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status)); - return status; - } - - return 0; -} - -#endif /* PJ_HAS_TCP */ - - -#else -/* To prevent warning about "translation unit is empty" - * when this test is disabled. - */ -int dummy_uiq_tcp; -#endif /* INCLUDE_TCP_IOQUEUE_TEST */ - - +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/ioq_tcp.c 4 10/29/05 10:23p Bennylp $ + */ +/* + * $Log: /pjproject-0.3/pjlib/src/pjlib-test/ioq_tcp.c $ + * + * 4 10/29/05 10:23p Bennylp + * Fixed no-memory exception. + * + * 3 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + */ +#include "test.h" + +/** + * \page page_pjlib_ioqueue_tcp_test Test: I/O Queue (TCP) + * + * This file provides implementation to test the + * functionality of the I/O queue when TCP socket is used. + * + * + * This file is pjlib-test/ioq_tcp.c + * + * \include pjlib-test/ioq_tcp.c + */ + + +#if INCLUDE_TCP_IOQUEUE_TEST + +#include + +#if PJ_HAS_TCP + +#define THIS_FILE "test_tcp" +#define PORT 50000 +#define NON_EXISTANT_PORT 50123 +#define LOOP 100 +#define BUF_MIN_SIZE 32 +#define BUF_MAX_SIZE 2048 +#define SOCK_INACTIVE_MIN (4-2) +#define SOCK_INACTIVE_MAX (PJ_IOQUEUE_MAX_HANDLES - 2) +#define POOL_SIZE (2*BUF_MAX_SIZE + SOCK_INACTIVE_MAX*128 + 2048) + +static pj_ssize_t callback_read_size, + callback_write_size, + callback_accept_status, + callback_connect_status; +static pj_ioqueue_key_t*callback_read_key, + *callback_write_key, + *callback_accept_key, + *callback_connect_key; + +static void on_ioqueue_read(pj_ioqueue_key_t *key, pj_ssize_t bytes_read) +{ + callback_read_key = key; + callback_read_size = bytes_read; +} + +static void on_ioqueue_write(pj_ioqueue_key_t *key, pj_ssize_t bytes_written) +{ + callback_write_key = key; + callback_write_size = bytes_written; +} + +static void on_ioqueue_accept(pj_ioqueue_key_t *key, pj_sock_t sock, + int status) +{ + PJ_UNUSED_ARG(sock); + + callback_accept_key = key; + callback_accept_status = status; +} + +static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status) +{ + callback_connect_key = key; + callback_connect_status = status; +} + +static pj_ioqueue_callback test_cb = +{ + &on_ioqueue_read, + &on_ioqueue_write, + &on_ioqueue_accept, + &on_ioqueue_connect, +}; + +static int send_recv_test(pj_ioqueue_t *ioque, + pj_ioqueue_key_t *skey, + pj_ioqueue_key_t *ckey, + void *send_buf, + void *recv_buf, + pj_ssize_t bufsize, + pj_timestamp *t_elapsed) +{ + int rc; + pj_ssize_t bytes; + pj_timestamp t1, t2; + int pending_op = 0; + + // Start reading on the server side. + rc = pj_ioqueue_read(ioque, skey, recv_buf, bufsize); + if (rc != 0 && rc != PJ_EPENDING) { + return -100; + } + + ++pending_op; + + // Randomize send buffer. + pj_create_random_string((char*)send_buf, bufsize); + + // Starts send on the client side. + bytes = pj_ioqueue_write(ioque, ckey, send_buf, bufsize); + if (bytes != bufsize && bytes != PJ_EPENDING) { + return -120; + } + if (bytes == PJ_EPENDING) { + ++pending_op; + } + + // Begin time. + pj_get_timestamp(&t1); + + // Reset indicators + callback_read_size = callback_write_size = 0; + callback_read_key = callback_write_key = NULL; + + // Poll the queue until we've got completion event in the server side. + rc = 0; + while (pending_op > 0) { + rc = pj_ioqueue_poll(ioque, NULL); + if (rc > 0) { + if (callback_read_size) { + if (callback_read_size != bufsize) { + return -160; + } + if (callback_read_key != skey) + return -161; + } + if (callback_write_size) { + if (callback_write_key != ckey) + return -162; + } + pending_op -= rc; + } + if (rc < 0) { + return -170; + } + } + + // End time. + pj_get_timestamp(&t2); + t_elapsed->u32.lo += (t2.u32.lo - t1.u32.lo); + + if (rc < 0) { + return -150; + } + + // Compare recv buffer with send buffer. + if (pj_memcmp(send_buf, recv_buf, bufsize) != 0) { + return -180; + } + + // Success + return 0; +} + + +/* + * Compliance test for success scenario. + */ +static int compliance_test_0(void) +{ + pj_sock_t ssock=-1, csock0=-1, csock1=-1; + pj_sockaddr_in addr, client_addr, rmt_addr; + int client_addr_len; + pj_pool_t *pool = NULL; + char *send_buf, *recv_buf; + pj_ioqueue_t *ioque = NULL; + pj_ioqueue_key_t *skey, *ckey0, *ckey1; + int bufsize = BUF_MIN_SIZE; + pj_ssize_t status = -1; + int pending_op = 0; + pj_timestamp t_elapsed; + pj_str_t s; + pj_status_t rc; + + // Create pool. + pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL); + + // Allocate buffers for send and receive. + send_buf = (char*)pj_pool_alloc(pool, bufsize); + recv_buf = (char*)pj_pool_alloc(pool, bufsize); + + // Create server socket and client socket for connecting + rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &ssock); + if (rc != PJ_SUCCESS) { + app_perror("...error creating socket", rc); + status=-1; goto on_error; + } + + rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &csock1); + if (rc != PJ_SUCCESS) { + app_perror("...error creating socket", rc); + status=-1; goto on_error; + } + + // Bind server socket. + memset(&addr, 0, sizeof(addr)); + addr.sin_family = PJ_AF_INET; + addr.sin_port = pj_htons(PORT); + if (pj_sock_bind(ssock, &addr, sizeof(addr))) { + app_perror("...bind error", rc); + status=-10; goto on_error; + } + + // Create I/O Queue. + rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, 0, &ioque); + if (rc != PJ_SUCCESS) { + app_perror("...ERROR in pj_ioqueue_create()", rc); + status=-20; goto on_error; + } + + // Register server socket and client socket. + rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, &test_cb, &skey); + if (rc == PJ_SUCCESS) + rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL, &test_cb, + &ckey1); + else + ckey1 = NULL; + if (rc != PJ_SUCCESS) { + app_perror("...ERROR in pj_ioqueue_register_sock()", rc); + status=-23; goto on_error; + } + + // Server socket listen(). + if (pj_sock_listen(ssock, 5)) { + app_perror("...ERROR in pj_sock_listen()", rc); + status=-25; goto on_error; + } + + // Server socket accept() + client_addr_len = sizeof(pj_sockaddr_in); + status = pj_ioqueue_accept(ioque, skey, &csock0, &client_addr, &rmt_addr, &client_addr_len); + if (status != PJ_EPENDING) { + app_perror("...ERROR in pj_ioqueue_accept()", rc); + status=-30; goto on_error; + } + if (status==PJ_EPENDING) { + ++pending_op; + } + + // Initialize remote address. + memset(&addr, 0, sizeof(addr)); + addr.sin_family = PJ_AF_INET; + addr.sin_port = pj_htons(PORT); + addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1")); + + // Client socket connect() + status = pj_ioqueue_connect(ioque, ckey1, &addr, sizeof(addr)); + if (status!=PJ_SUCCESS && status != PJ_EPENDING) { + app_perror("...ERROR in pj_ioqueue_connect()", rc); + status=-40; goto on_error; + } + if (status==PJ_EPENDING) { + ++pending_op; + } + + // Poll until connected + callback_read_size = callback_write_size = 0; + callback_accept_status = callback_connect_status = -2; + + callback_read_key = callback_write_key = + callback_accept_key = callback_connect_key = NULL; + + while (pending_op) { + pj_time_val timeout = {1, 0}; + + status=pj_ioqueue_poll(ioque, &timeout); + if (status > 0) { + if (callback_accept_status != -2) { + if (callback_accept_status != 0) { + status=-41; goto on_error; + } + if (callback_accept_key != skey) { + status=-41; goto on_error; + } + } + + if (callback_connect_status != -2) { + if (callback_connect_status != 0) { + status=-50; goto on_error; + } + if (callback_connect_key != ckey1) { + status=-51; goto on_error; + } + } + + pending_op -= status; + + if (pending_op == 0) { + status = 0; + } + } + } + + // Check accepted socket. + if (csock0 == PJ_INVALID_SOCKET) { + status = -69; + app_perror("...accept() error", pj_get_os_error()); + goto on_error; + } + + // Register newly accepted socket. + rc = pj_ioqueue_register_sock(pool, ioque, csock0, NULL, + &test_cb, &ckey0); + if (rc != PJ_SUCCESS) { + app_perror("...ERROR in pj_ioqueue_register_sock", rc); + status = -70; + goto on_error; + } + + // Test send and receive. + t_elapsed.u32.lo = 0; + status = send_recv_test(ioque, ckey0, ckey1, send_buf, recv_buf, bufsize, &t_elapsed); + if (status != 0) { + goto on_error; + } + + // Success + status = 0; + +on_error: + if (ssock != PJ_INVALID_SOCKET) + pj_sock_close(ssock); + if (csock1 != PJ_INVALID_SOCKET) + pj_sock_close(csock1); + if (csock0 != PJ_INVALID_SOCKET) + pj_sock_close(csock0); + if (ioque != NULL) + pj_ioqueue_destroy(ioque); + pj_pool_release(pool); + return status; + +} + +/* + * Compliance test for failed scenario. + * In this case, the client connects to a non-existant service. + */ +static int compliance_test_1(void) +{ + pj_sock_t csock1=-1; + pj_sockaddr_in addr; + pj_pool_t *pool = NULL; + pj_ioqueue_t *ioque = NULL; + pj_ioqueue_key_t *ckey1; + pj_ssize_t status = -1; + int pending_op = 0; + pj_str_t s; + pj_status_t rc; + + // Create pool. + pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL); + + // Create I/O Queue. + rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, 0, &ioque); + if (!ioque) { + status=-20; goto on_error; + } + + // Create client socket + rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &csock1); + if (rc != PJ_SUCCESS) { + app_perror("...ERROR in pj_sock_socket()", rc); + status=-1; goto on_error; + } + + // Register client socket. + rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL, + &test_cb, &ckey1); + if (rc != PJ_SUCCESS) { + app_perror("...ERROR in pj_ioqueue_register_sock()", rc); + status=-23; goto on_error; + } + + // Initialize remote address. + memset(&addr, 0, sizeof(addr)); + addr.sin_family = PJ_AF_INET; + addr.sin_port = pj_htons(NON_EXISTANT_PORT); + addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1")); + + // Client socket connect() + status = pj_ioqueue_connect(ioque, ckey1, &addr, sizeof(addr)); + if (status==PJ_SUCCESS) { + // unexpectedly success! + status = -30; + goto on_error; + } + if (status != PJ_EPENDING) { + // success + } else { + ++pending_op; + } + + callback_connect_status = -2; + callback_connect_key = NULL; + + // Poll until we've got result + while (pending_op) { + pj_time_val timeout = {1, 0}; + + status=pj_ioqueue_poll(ioque, &timeout); + if (status > 0) { + if (callback_connect_key==ckey1) { + if (callback_connect_status == 0) { + // unexpectedly connected! + status = -50; + goto on_error; + } + } + + pending_op -= status; + if (pending_op == 0) { + status = 0; + } + } + } + + // Success + status = 0; + +on_error: + if (csock1 != PJ_INVALID_SOCKET) + pj_sock_close(csock1); + if (ioque != NULL) + pj_ioqueue_destroy(ioque); + pj_pool_release(pool); + return status; +} + +int tcp_ioqueue_test() +{ + int status; + + PJ_LOG(3, (THIS_FILE, "..compliance test 0 (success scenario)")); + if ((status=compliance_test_0()) != 0) { + PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status)); + return status; + } + PJ_LOG(3, (THIS_FILE, "..compliance test 1 (failed scenario)")); + if ((status=compliance_test_1()) != 0) { + PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status)); + return status; + } + + return 0; +} + +#endif /* PJ_HAS_TCP */ + + +#else +/* To prevent warning about "translation unit is empty" + * when this test is disabled. + */ +int dummy_uiq_tcp; +#endif /* INCLUDE_TCP_IOQUEUE_TEST */ + + diff --git a/pjlib/src/pjlib-test/ioq_udp.c b/pjlib/src/pjlib-test/ioq_udp.c index 8b95782a..8c15ecae 100644 --- a/pjlib/src/pjlib-test/ioq_udp.c +++ b/pjlib/src/pjlib-test/ioq_udp.c @@ -1,664 +1,664 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/ioq_udp.c 4 10/29/05 10:23p Bennylp $ - */ -/* - * $Log: /pjproject-0.3/pjlib/src/pjlib-test/ioq_udp.c $ - * - * 4 10/29/05 10:23p Bennylp - * Fixed no-memory exception. - * - * 3 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - */ -#include "test.h" - - -/** - * \page page_pjlib_ioqueue_udp_test Test: I/O Queue (UDP) - * - * This file provides implementation to test the - * functionality of the I/O queue when UDP socket is used. - * - * - * This file is pjlib-test/ioq_udp.c - * - * \include pjlib-test/ioq_udp.c - */ - - -#if INCLUDE_UDP_IOQUEUE_TEST - -#include - -#include - -#define THIS_FILE "test_udp" -#define PORT 51233 -#define LOOP 100 -#define BUF_MIN_SIZE 32 -#define BUF_MAX_SIZE 2048 -#define SOCK_INACTIVE_MIN (1) -#define SOCK_INACTIVE_MAX (PJ_IOQUEUE_MAX_HANDLES - 2) -#define POOL_SIZE (2*BUF_MAX_SIZE + SOCK_INACTIVE_MAX*128 + 2048) - -#undef TRACE_ -#define TRACE_(msg) PJ_LOG(3,(THIS_FILE,"....." msg)) - -static pj_ssize_t callback_read_size, - callback_write_size, - callback_accept_status, - callback_connect_status; -static pj_ioqueue_key_t *callback_read_key, - *callback_write_key, - *callback_accept_key, - *callback_connect_key; - -static void on_ioqueue_read(pj_ioqueue_key_t *key, pj_ssize_t bytes_read) -{ - callback_read_key = key; - callback_read_size = bytes_read; -} - -static void on_ioqueue_write(pj_ioqueue_key_t *key, pj_ssize_t bytes_written) -{ - callback_write_key = key; - callback_write_size = bytes_written; -} - -static void on_ioqueue_accept(pj_ioqueue_key_t *key, pj_sock_t sock, int status) -{ - PJ_UNUSED_ARG(sock); - callback_accept_key = key; - callback_accept_status = status; -} - -static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status) -{ - callback_connect_key = key; - callback_connect_status = status; -} - -static pj_ioqueue_callback test_cb = -{ - &on_ioqueue_read, - &on_ioqueue_write, - &on_ioqueue_accept, - &on_ioqueue_connect, -}; - -#ifdef PJ_WIN32 -# define S_ADDR S_un.S_addr -#else -# define S_ADDR s_addr -#endif - -/* - * native_format_test() - * This is just a simple test to verify that various structures in sock.h - * are really compatible with operating system's definitions. - */ -static int native_format_test(void) -{ - pj_status_t rc; - - // Test that PJ_INVALID_SOCKET is working. - { - pj_sock_t sock; - rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, -1, &sock); - if (rc == PJ_SUCCESS) - return -1020; - } - - // Previous func will set errno var. - pj_set_os_error(PJ_SUCCESS); - - return 0; -} - -/* - * compliance_test() - * To test that the basic IOQueue functionality works. It will just exchange - * data between two sockets. - */ -static int compliance_test(void) -{ - pj_sock_t ssock=-1, csock=-1; - pj_sockaddr_in addr; - int addrlen; - pj_pool_t *pool = NULL; - char *send_buf, *recv_buf; - pj_ioqueue_t *ioque = NULL; - pj_ioqueue_key_t *skey, *ckey; - int bufsize = BUF_MIN_SIZE; - pj_ssize_t bytes, status = -1; - pj_str_t temp; - pj_bool_t send_pending, recv_pending; - pj_status_t rc; - - pj_set_os_error(PJ_SUCCESS); - - // Create pool. - pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL); - - // Allocate buffers for send and receive. - send_buf = (char*)pj_pool_alloc(pool, bufsize); - recv_buf = (char*)pj_pool_alloc(pool, bufsize); - - // Allocate sockets for sending and receiving. - TRACE_("creating sockets..."); - rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ssock); - if (rc==PJ_SUCCESS) - rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &csock); - else - csock = PJ_INVALID_SOCKET; - if (rc != PJ_SUCCESS) { - app_perror("...ERROR in pj_sock_socket()", rc); - status=-1; goto on_error; - } - - // Bind server socket. - TRACE_("bind socket..."); - memset(&addr, 0, sizeof(addr)); - addr.sin_family = PJ_AF_INET; - addr.sin_port = pj_htons(PORT); - if (pj_sock_bind(ssock, &addr, sizeof(addr))) { - status=-10; goto on_error; - } - - // Create I/O Queue. - TRACE_("create ioqueue..."); - rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, - PJ_IOQUEUE_DEFAULT_THREADS, &ioque); - if (rc != PJ_SUCCESS) { - status=-20; goto on_error; - } - - // Register server and client socket. - // We put this after inactivity socket, hopefully this can represent the - // worst waiting time. - TRACE_("registering first sockets..."); - rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, - &test_cb, &skey); - if (rc != PJ_SUCCESS) { - app_perror("...error(10): ioqueue_register error", rc); - status=-25; goto on_error; - } - TRACE_("registering second sockets..."); - rc = pj_ioqueue_register_sock( pool, ioque, csock, NULL, - &test_cb, &ckey); - if (rc != PJ_SUCCESS) { - app_perror("...error(11): ioqueue_register error", rc); - status=-26; goto on_error; - } - - // Set destination address to send the packet. - TRACE_("set destination address..."); - temp = pj_str("127.0.0.1"); - if ((rc=pj_sockaddr_in_init(&addr, &temp, PORT)) != 0) { - app_perror("...error: unable to resolve 127.0.0.1", rc); - status=-26; goto on_error; - } - - // Randomize send_buf. - pj_create_random_string(send_buf, bufsize); - - // Register reading from ioqueue. - TRACE_("start recvfrom..."); - addrlen = sizeof(addr); - bytes = pj_ioqueue_recvfrom(ioque, skey, recv_buf, bufsize, 0, - &addr, &addrlen); - if (bytes < 0 && bytes != PJ_EPENDING) { - status=-28; goto on_error; - } else if (bytes == PJ_EPENDING) { - recv_pending = 1; - PJ_LOG(3, (THIS_FILE, - "......ok: recvfrom returned pending")); - } else { - PJ_LOG(3, (THIS_FILE, - "......error: recvfrom returned immediate ok!")); - status=-29; goto on_error; - } - - // Write must return the number of bytes. - TRACE_("start sendto..."); - bytes = pj_ioqueue_sendto(ioque, ckey, send_buf, bufsize, 0, &addr, - sizeof(addr)); - if (bytes != bufsize && bytes != PJ_EPENDING) { - PJ_LOG(1,(THIS_FILE, - "......error: sendto returned %d", bytes)); - status=-30; goto on_error; - } else if (bytes == PJ_EPENDING) { - send_pending = 1; - PJ_LOG(3, (THIS_FILE, - "......ok: sendto returned pending")); - } else { - send_pending = 0; - PJ_LOG(3, (THIS_FILE, - "......ok: sendto returned immediate success")); - } - - // reset callback variables. - callback_read_size = callback_write_size = 0; - callback_accept_status = callback_connect_status = -2; - callback_read_key = callback_write_key = - callback_accept_key = callback_connect_key = NULL; - - // Poll if pending. - while (send_pending && recv_pending) { - int rc; - pj_time_val timeout = { 5, 0 }; - - TRACE_("poll..."); - rc = pj_ioqueue_poll(ioque, &timeout); - - if (rc == 0) { - PJ_LOG(1,(THIS_FILE, "...ERROR: timed out...")); - status=-45; goto on_error; - } else if (rc < 0) { - app_perror("...ERROR in ioqueue_poll()", rc); - status=-50; goto on_error; - } - - if (callback_read_key != NULL) { - if (callback_read_size != bufsize) { - status=-61; goto on_error; - } - - if (callback_read_key != skey) { - status=-65; goto on_error; - } - - if (memcmp(send_buf, recv_buf, bufsize) != 0) { - status=-70; goto on_error; - } - - - recv_pending = 0; - } - - if (callback_write_key != NULL) { - if (callback_write_size != bufsize) { - status=-73; goto on_error; - } - - if (callback_write_key != ckey) { - status=-75; goto on_error; - } - - send_pending = 0; - } - } - - // Success - status = 0; - -on_error: - if (status != 0) { - char errbuf[128]; - PJ_LOG(1, (THIS_FILE, - "...compliance test error: status=%d, os_err=%d (%s)", - status, pj_get_netos_error(), - pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf)))); - } - if (ssock) - pj_sock_close(ssock); - if (csock) - pj_sock_close(csock); - if (ioque != NULL) - pj_ioqueue_destroy(ioque); - pj_pool_release(pool); - return status; - -} - -/* - * Testing with many handles. - * This will just test registering PJ_IOQUEUE_MAX_HANDLES count - * of sockets to the ioqueue. - */ -static int many_handles_test(void) -{ - enum { MAX = PJ_IOQUEUE_MAX_HANDLES }; - pj_pool_t *pool; - pj_ioqueue_t *ioqueue; - pj_sock_t *sock; - pj_ioqueue_key_t **key; - pj_status_t rc; - int count, i; - - PJ_LOG(3,(THIS_FILE,"...testing with so many handles")); - - pool = pj_pool_create(mem, NULL, 4000, 4000, NULL); - if (!pool) - return PJ_ENOMEM; - - key = pj_pool_alloc(pool, MAX*sizeof(pj_ioqueue_key_t*)); - sock = pj_pool_alloc(pool, MAX*sizeof(pj_sock_t)); - - /* Create IOQueue */ - rc = pj_ioqueue_create(pool, MAX, - PJ_IOQUEUE_DEFAULT_THREADS, - &ioqueue); - if (rc != PJ_SUCCESS || ioqueue == NULL) { - app_perror("...error in pj_ioqueue_create", rc); - return -10; - } - - /* Register as many sockets. */ - for (count=0; count= 0 && callback_read_key != skey); - - // End time. - pj_get_timestamp(&t2); - t_elapsed.u64 += (t2.u64 - t1.u64); - - if (rc < 0) - break; - - // Compare recv buffer with send buffer. - if (callback_read_size != bufsize || - memcmp(send_buf, recv_buf, bufsize)) - { - rc = -1; - break; - } - - // Poll until all events are exhausted, before we start the next loop. - do { - pj_time_val timeout = { 0, 10 }; - rc = pj_ioqueue_poll(ioque, &timeout); - } while (rc>0); - - rc = 0; - } - - // Print results - if (rc == 0) { - pj_timestamp tzero; - pj_uint32_t usec_delay; - - tzero.u32.hi = tzero.u32.lo = 0; - usec_delay = pj_elapsed_usec( &tzero, &t_elapsed); - - PJ_LOG(3, (THIS_FILE, "...%10d %15d % 9d", - bufsize, inactive_sock_count, usec_delay)); - - } else { - PJ_LOG(2, (THIS_FILE, "...ERROR (buf:%d, fds:%d)", - bufsize, inactive_sock_count+2)); - } - - // Cleaning up. - for (i=0; ipjlib-test/ioq_udp.c + * + * \include pjlib-test/ioq_udp.c + */ + + +#if INCLUDE_UDP_IOQUEUE_TEST + +#include + +#include + +#define THIS_FILE "test_udp" +#define PORT 51233 +#define LOOP 100 +#define BUF_MIN_SIZE 32 +#define BUF_MAX_SIZE 2048 +#define SOCK_INACTIVE_MIN (1) +#define SOCK_INACTIVE_MAX (PJ_IOQUEUE_MAX_HANDLES - 2) +#define POOL_SIZE (2*BUF_MAX_SIZE + SOCK_INACTIVE_MAX*128 + 2048) + +#undef TRACE_ +#define TRACE_(msg) PJ_LOG(3,(THIS_FILE,"....." msg)) + +static pj_ssize_t callback_read_size, + callback_write_size, + callback_accept_status, + callback_connect_status; +static pj_ioqueue_key_t *callback_read_key, + *callback_write_key, + *callback_accept_key, + *callback_connect_key; + +static void on_ioqueue_read(pj_ioqueue_key_t *key, pj_ssize_t bytes_read) +{ + callback_read_key = key; + callback_read_size = bytes_read; +} + +static void on_ioqueue_write(pj_ioqueue_key_t *key, pj_ssize_t bytes_written) +{ + callback_write_key = key; + callback_write_size = bytes_written; +} + +static void on_ioqueue_accept(pj_ioqueue_key_t *key, pj_sock_t sock, int status) +{ + PJ_UNUSED_ARG(sock); + callback_accept_key = key; + callback_accept_status = status; +} + +static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status) +{ + callback_connect_key = key; + callback_connect_status = status; +} + +static pj_ioqueue_callback test_cb = +{ + &on_ioqueue_read, + &on_ioqueue_write, + &on_ioqueue_accept, + &on_ioqueue_connect, +}; + +#ifdef PJ_WIN32 +# define S_ADDR S_un.S_addr +#else +# define S_ADDR s_addr +#endif + +/* + * native_format_test() + * This is just a simple test to verify that various structures in sock.h + * are really compatible with operating system's definitions. + */ +static int native_format_test(void) +{ + pj_status_t rc; + + // Test that PJ_INVALID_SOCKET is working. + { + pj_sock_t sock; + rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, -1, &sock); + if (rc == PJ_SUCCESS) + return -1020; + } + + // Previous func will set errno var. + pj_set_os_error(PJ_SUCCESS); + + return 0; +} + +/* + * compliance_test() + * To test that the basic IOQueue functionality works. It will just exchange + * data between two sockets. + */ +static int compliance_test(void) +{ + pj_sock_t ssock=-1, csock=-1; + pj_sockaddr_in addr; + int addrlen; + pj_pool_t *pool = NULL; + char *send_buf, *recv_buf; + pj_ioqueue_t *ioque = NULL; + pj_ioqueue_key_t *skey, *ckey; + int bufsize = BUF_MIN_SIZE; + pj_ssize_t bytes, status = -1; + pj_str_t temp; + pj_bool_t send_pending, recv_pending; + pj_status_t rc; + + pj_set_os_error(PJ_SUCCESS); + + // Create pool. + pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL); + + // Allocate buffers for send and receive. + send_buf = (char*)pj_pool_alloc(pool, bufsize); + recv_buf = (char*)pj_pool_alloc(pool, bufsize); + + // Allocate sockets for sending and receiving. + TRACE_("creating sockets..."); + rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ssock); + if (rc==PJ_SUCCESS) + rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &csock); + else + csock = PJ_INVALID_SOCKET; + if (rc != PJ_SUCCESS) { + app_perror("...ERROR in pj_sock_socket()", rc); + status=-1; goto on_error; + } + + // Bind server socket. + TRACE_("bind socket..."); + memset(&addr, 0, sizeof(addr)); + addr.sin_family = PJ_AF_INET; + addr.sin_port = pj_htons(PORT); + if (pj_sock_bind(ssock, &addr, sizeof(addr))) { + status=-10; goto on_error; + } + + // Create I/O Queue. + TRACE_("create ioqueue..."); + rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, + PJ_IOQUEUE_DEFAULT_THREADS, &ioque); + if (rc != PJ_SUCCESS) { + status=-20; goto on_error; + } + + // Register server and client socket. + // We put this after inactivity socket, hopefully this can represent the + // worst waiting time. + TRACE_("registering first sockets..."); + rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, + &test_cb, &skey); + if (rc != PJ_SUCCESS) { + app_perror("...error(10): ioqueue_register error", rc); + status=-25; goto on_error; + } + TRACE_("registering second sockets..."); + rc = pj_ioqueue_register_sock( pool, ioque, csock, NULL, + &test_cb, &ckey); + if (rc != PJ_SUCCESS) { + app_perror("...error(11): ioqueue_register error", rc); + status=-26; goto on_error; + } + + // Set destination address to send the packet. + TRACE_("set destination address..."); + temp = pj_str("127.0.0.1"); + if ((rc=pj_sockaddr_in_init(&addr, &temp, PORT)) != 0) { + app_perror("...error: unable to resolve 127.0.0.1", rc); + status=-26; goto on_error; + } + + // Randomize send_buf. + pj_create_random_string(send_buf, bufsize); + + // Register reading from ioqueue. + TRACE_("start recvfrom..."); + addrlen = sizeof(addr); + bytes = pj_ioqueue_recvfrom(ioque, skey, recv_buf, bufsize, 0, + &addr, &addrlen); + if (bytes < 0 && bytes != PJ_EPENDING) { + status=-28; goto on_error; + } else if (bytes == PJ_EPENDING) { + recv_pending = 1; + PJ_LOG(3, (THIS_FILE, + "......ok: recvfrom returned pending")); + } else { + PJ_LOG(3, (THIS_FILE, + "......error: recvfrom returned immediate ok!")); + status=-29; goto on_error; + } + + // Write must return the number of bytes. + TRACE_("start sendto..."); + bytes = pj_ioqueue_sendto(ioque, ckey, send_buf, bufsize, 0, &addr, + sizeof(addr)); + if (bytes != bufsize && bytes != PJ_EPENDING) { + PJ_LOG(1,(THIS_FILE, + "......error: sendto returned %d", bytes)); + status=-30; goto on_error; + } else if (bytes == PJ_EPENDING) { + send_pending = 1; + PJ_LOG(3, (THIS_FILE, + "......ok: sendto returned pending")); + } else { + send_pending = 0; + PJ_LOG(3, (THIS_FILE, + "......ok: sendto returned immediate success")); + } + + // reset callback variables. + callback_read_size = callback_write_size = 0; + callback_accept_status = callback_connect_status = -2; + callback_read_key = callback_write_key = + callback_accept_key = callback_connect_key = NULL; + + // Poll if pending. + while (send_pending && recv_pending) { + int rc; + pj_time_val timeout = { 5, 0 }; + + TRACE_("poll..."); + rc = pj_ioqueue_poll(ioque, &timeout); + + if (rc == 0) { + PJ_LOG(1,(THIS_FILE, "...ERROR: timed out...")); + status=-45; goto on_error; + } else if (rc < 0) { + app_perror("...ERROR in ioqueue_poll()", rc); + status=-50; goto on_error; + } + + if (callback_read_key != NULL) { + if (callback_read_size != bufsize) { + status=-61; goto on_error; + } + + if (callback_read_key != skey) { + status=-65; goto on_error; + } + + if (memcmp(send_buf, recv_buf, bufsize) != 0) { + status=-70; goto on_error; + } + + + recv_pending = 0; + } + + if (callback_write_key != NULL) { + if (callback_write_size != bufsize) { + status=-73; goto on_error; + } + + if (callback_write_key != ckey) { + status=-75; goto on_error; + } + + send_pending = 0; + } + } + + // Success + status = 0; + +on_error: + if (status != 0) { + char errbuf[128]; + PJ_LOG(1, (THIS_FILE, + "...compliance test error: status=%d, os_err=%d (%s)", + status, pj_get_netos_error(), + pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf)))); + } + if (ssock) + pj_sock_close(ssock); + if (csock) + pj_sock_close(csock); + if (ioque != NULL) + pj_ioqueue_destroy(ioque); + pj_pool_release(pool); + return status; + +} + +/* + * Testing with many handles. + * This will just test registering PJ_IOQUEUE_MAX_HANDLES count + * of sockets to the ioqueue. + */ +static int many_handles_test(void) +{ + enum { MAX = PJ_IOQUEUE_MAX_HANDLES }; + pj_pool_t *pool; + pj_ioqueue_t *ioqueue; + pj_sock_t *sock; + pj_ioqueue_key_t **key; + pj_status_t rc; + int count, i; + + PJ_LOG(3,(THIS_FILE,"...testing with so many handles")); + + pool = pj_pool_create(mem, NULL, 4000, 4000, NULL); + if (!pool) + return PJ_ENOMEM; + + key = pj_pool_alloc(pool, MAX*sizeof(pj_ioqueue_key_t*)); + sock = pj_pool_alloc(pool, MAX*sizeof(pj_sock_t)); + + /* Create IOQueue */ + rc = pj_ioqueue_create(pool, MAX, + PJ_IOQUEUE_DEFAULT_THREADS, + &ioqueue); + if (rc != PJ_SUCCESS || ioqueue == NULL) { + app_perror("...error in pj_ioqueue_create", rc); + return -10; + } + + /* Register as many sockets. */ + for (count=0; count= 0 && callback_read_key != skey); + + // End time. + pj_get_timestamp(&t2); + t_elapsed.u64 += (t2.u64 - t1.u64); + + if (rc < 0) + break; + + // Compare recv buffer with send buffer. + if (callback_read_size != bufsize || + memcmp(send_buf, recv_buf, bufsize)) + { + rc = -1; + break; + } + + // Poll until all events are exhausted, before we start the next loop. + do { + pj_time_val timeout = { 0, 10 }; + rc = pj_ioqueue_poll(ioque, &timeout); + } while (rc>0); + + rc = 0; + } + + // Print results + if (rc == 0) { + pj_timestamp tzero; + pj_uint32_t usec_delay; + + tzero.u32.hi = tzero.u32.lo = 0; + usec_delay = pj_elapsed_usec( &tzero, &t_elapsed); + + PJ_LOG(3, (THIS_FILE, "...%10d %15d % 9d", + bufsize, inactive_sock_count, usec_delay)); + + } else { + PJ_LOG(2, (THIS_FILE, "...ERROR (buf:%d, fds:%d)", + bufsize, inactive_sock_count+2)); + } + + // Cleaning up. + for (i=0; ipjlib-test/list.c - * - * \include pjlib-test/list.c - */ - -#if INCLUDE_LIST_TEST - -#include - -typedef struct list_node -{ - PJ_DECL_LIST_MEMBER(struct list_node) - int value; -} list_node; - -static int compare_node(void *value, const pj_list_type *nd) -{ - list_node *node = (list_node*)nd; - return ((int)value == node->value) ? 0 : -1; -} - -#define PJ_SIGNED_ARRAY_SIZE(a) ((int)PJ_ARRAY_SIZE(a)) - -int list_test() -{ - list_node nodes[4]; // must be even number of nodes - list_node list; - list_node list2; - list_node *p; - int i; // don't change to unsigned! - - // - // Test insert_before(). - // - list.value = (unsigned)-1; - pj_list_init(&list); - for (i=0; inext) { - pj_assert(p->value == i); - if (p->value != i) { - return -1; - } - } - - // - // Test insert_after() - // - pj_list_init(&list); - for (i=PJ_SIGNED_ARRAY_SIZE(nodes)-1; i>=0; --i) { - pj_list_insert_after(&list, &nodes[i]); - } - // check. - for (i=0, p=list.next; inext) { - pj_assert(p->value == i); - if (p->value != i) { - return -1; - } - } - - // - // Test merge_last() - // - // Init lists - pj_list_init(&list); - pj_list_init(&list2); - for (i=0; inext) { - pj_assert(p->value == i); - if (p->value != i) { - return -1; - } - } - // check list is empty - pj_assert( pj_list_empty(&list2) ); - if (!pj_list_empty(&list2)) { - return -1; - } - - // - // Check merge_first() - // - pj_list_init(&list); - pj_list_init(&list2); - for (i=0; inext) { - pj_assert(p->value == i); - if (p->value != i) { - return -1; - } - } - // check list is empty - pj_assert( pj_list_empty(&list) ); - if (!pj_list_empty(&list)) { - return -1; - } - - // - // Test insert_nodes_before() - // - // init list - pj_list_init(&list); - for (i=0; inext) { - pj_assert(p->value == i); - if (p->value != i) { - return -1; - } - } - - // erase test. - pj_list_init(&list); - for (i=0; i=0; --i) { - int j; - pj_list_erase(&nodes[i]); - for (j=0, p=list.next; jnext) { - pj_assert(p->value == j); - if (p->value != j) { - return -1; - } - } - } - - // find and search - pj_list_init(&list); - for (i=0; ipjlib-test/list.c + * + * \include pjlib-test/list.c + */ + +#if INCLUDE_LIST_TEST + +#include + +typedef struct list_node +{ + PJ_DECL_LIST_MEMBER(struct list_node) + int value; +} list_node; + +static int compare_node(void *value, const pj_list_type *nd) +{ + list_node *node = (list_node*)nd; + return ((int)value == node->value) ? 0 : -1; +} + +#define PJ_SIGNED_ARRAY_SIZE(a) ((int)PJ_ARRAY_SIZE(a)) + +int list_test() +{ + list_node nodes[4]; // must be even number of nodes + list_node list; + list_node list2; + list_node *p; + int i; // don't change to unsigned! + + // + // Test insert_before(). + // + list.value = (unsigned)-1; + pj_list_init(&list); + for (i=0; inext) { + pj_assert(p->value == i); + if (p->value != i) { + return -1; + } + } + + // + // Test insert_after() + // + pj_list_init(&list); + for (i=PJ_SIGNED_ARRAY_SIZE(nodes)-1; i>=0; --i) { + pj_list_insert_after(&list, &nodes[i]); + } + // check. + for (i=0, p=list.next; inext) { + pj_assert(p->value == i); + if (p->value != i) { + return -1; + } + } + + // + // Test merge_last() + // + // Init lists + pj_list_init(&list); + pj_list_init(&list2); + for (i=0; inext) { + pj_assert(p->value == i); + if (p->value != i) { + return -1; + } + } + // check list is empty + pj_assert( pj_list_empty(&list2) ); + if (!pj_list_empty(&list2)) { + return -1; + } + + // + // Check merge_first() + // + pj_list_init(&list); + pj_list_init(&list2); + for (i=0; inext) { + pj_assert(p->value == i); + if (p->value != i) { + return -1; + } + } + // check list is empty + pj_assert( pj_list_empty(&list) ); + if (!pj_list_empty(&list)) { + return -1; + } + + // + // Test insert_nodes_before() + // + // init list + pj_list_init(&list); + for (i=0; inext) { + pj_assert(p->value == i); + if (p->value != i) { + return -1; + } + } + + // erase test. + pj_list_init(&list); + for (i=0; i=0; --i) { + int j; + pj_list_erase(&nodes[i]); + for (j=0, p=list.next; jnext) { + pj_assert(p->value == j); + if (p->value != j) { + return -1; + } + } + } + + // find and search + pj_list_init(&list); + for (i=0; i -#include -#include - -extern int param_echo_sock_type; -extern const char *param_echo_server; -extern int param_echo_port; - - -#if defined(PJ_WIN32) && PJ_WIN32!=0 -#include -static void boost(void) -{ - SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); -} -#else -#define boost() -#endif - -int main(int argc, char *argv[]) -{ - int rc; - - boost(); - - while (argc > 1) { - char *arg = argv[--argc]; - - if (*arg=='-' && *(arg+1)=='p') { - pj_str_t port = pj_str(argv[--argc]); - - param_echo_port = pj_strtoul(&port); - - } else if (*arg=='-' && *(arg+1)=='s') { - param_echo_server = argv[--argc]; - - } else if (*arg=='-' && *(arg+1)=='t') { - pj_str_t type = pj_str(argv[--argc]); - - if (pj_stricmp2(&type, "tcp")==0) - param_echo_sock_type = PJ_SOCK_STREAM; - else if (pj_stricmp2(&type, "udp")==0) - param_echo_sock_type = PJ_SOCK_DGRAM; - else { - PJ_LOG(3,("", "error: unknown socket type %s", type.ptr)); - return 1; - } - } - } - - rc = test_main(); - - return rc; -} - +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/main.c 4 29/10/05 21:32 Bennylp $ + */ +/* + * $Log: /pjproject-0.3/pjlib/src/pjlib-test/main.c $ + * + * 4 29/10/05 21:32 Bennylp + * Boost process priority in Win32 + * + * 3 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + */ +#include "test.h" + +#include +#include +#include + +extern int param_echo_sock_type; +extern const char *param_echo_server; +extern int param_echo_port; + + +#if defined(PJ_WIN32) && PJ_WIN32!=0 +#include +static void boost(void) +{ + SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); +} +#else +#define boost() +#endif + +#if defined(PJ_SUNOS) && PJ_SUNOS!=0 +#include +static void init_signals() +{ + struct sigaction act; + + memset(&act, 0, sizeof(act)); + act.sa_handler = SIG_IGN; + + sigaction(SIGALRM, &act, NULL); +} + +#else +#define init_signals() +#endif + +int main(int argc, char *argv[]) +{ + int rc; + + boost(); + init_signals(); + + while (argc > 1) { + char *arg = argv[--argc]; + + if (*arg=='-' && *(arg+1)=='p') { + pj_str_t port = pj_str(argv[--argc]); + + param_echo_port = pj_strtoul(&port); + + } else if (*arg=='-' && *(arg+1)=='s') { + param_echo_server = argv[--argc]; + + } else if (*arg=='-' && *(arg+1)=='t') { + pj_str_t type = pj_str(argv[--argc]); + + if (pj_stricmp2(&type, "tcp")==0) + param_echo_sock_type = PJ_SOCK_STREAM; + else if (pj_stricmp2(&type, "udp")==0) + param_echo_sock_type = PJ_SOCK_DGRAM; + else { + PJ_LOG(3,("", "error: unknown socket type %s", type.ptr)); + return 1; + } + } + } + + rc = test_main(); + + return rc; +} + diff --git a/pjlib/src/pjlib-test/main_mod.c b/pjlib/src/pjlib-test/main_mod.c index 45410184..26f5295c 100644 --- a/pjlib/src/pjlib-test/main_mod.c +++ b/pjlib/src/pjlib-test/main_mod.c @@ -1,33 +1,33 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/main_mod.c 2 10/29/05 11:51a Bennylp $ - */ -/* - * $Log: /pjproject-0.3/pjlib/src/pjlib-test/main_mod.c $ - * - * 2 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 1 10/05/05 5:12p Bennylp - * Created. - * - */ -#include "test.h" -#include -#include - -int init_module(void) -{ - printk(KERN_INFO "PJLIB test module loaded. Starting tests...\n"); - - test_main(); - - /* Prevent module from loading. We've finished test anyway.. */ - return 1; -} - -void cleanup_module(void) -{ - printk(KERN_INFO "PJLIB test module unloading...\n"); -} - -MODULE_LICENSE("GPL"); - +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/main_mod.c 2 10/29/05 11:51a Bennylp $ + */ +/* + * $Log: /pjproject-0.3/pjlib/src/pjlib-test/main_mod.c $ + * + * 2 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 1 10/05/05 5:12p Bennylp + * Created. + * + */ +#include "test.h" +#include +#include + +int init_module(void) +{ + printk(KERN_INFO "PJLIB test module loaded. Starting tests...\n"); + + test_main(); + + /* Prevent module from loading. We've finished test anyway.. */ + return 1; +} + +void cleanup_module(void) +{ + printk(KERN_INFO "PJLIB test module unloading...\n"); +} + +MODULE_LICENSE("GPL"); + diff --git a/pjlib/src/pjlib-test/mutex.c b/pjlib/src/pjlib-test/mutex.c index b6609b8d..a6fabb38 100644 --- a/pjlib/src/pjlib-test/mutex.c +++ b/pjlib/src/pjlib-test/mutex.c @@ -1,164 +1,164 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/mutex.c 1 10/23/05 12:52p Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pjlib-test/mutex.c $ - * - * 1 10/23/05 12:52p Bennylp - * Craeted. - * - */ -#include "test.h" -#include - -#if INCLUDE_MUTEX_TEST - -#undef TRACE_ -//#define TRACE_(x) PJ_LOG(3,x) -#define TRACE_(x) - -/* Test witn non-recursive mutex. */ -static int simple_mutex_test(pj_pool_t *pool) -{ - pj_status_t rc; - pj_mutex_t *mutex; - - PJ_LOG(3,("", "...testing simple mutex")); - - /* Create mutex. */ - TRACE_(("", "....create mutex")); - rc = pj_mutex_create( pool, "", PJ_MUTEX_SIMPLE, &mutex); - if (rc != PJ_SUCCESS) { - app_perror("...error: pj_mutex_create", rc); - return -10; - } - - /* Normal lock/unlock cycle. */ - TRACE_(("", "....lock mutex")); - rc = pj_mutex_lock(mutex); - if (rc != PJ_SUCCESS) { - app_perror("...error: pj_mutex_lock", rc); - return -20; - } - TRACE_(("", "....unlock mutex")); - rc = pj_mutex_unlock(mutex); - if (rc != PJ_SUCCESS) { - app_perror("...error: pj_mutex_unlock", rc); - return -30; - } - - /* Lock again. */ - TRACE_(("", "....lock mutex")); - rc = pj_mutex_lock(mutex); - if (rc != PJ_SUCCESS) return -40; - - /* Try-lock should fail. It should not deadlocked. */ - TRACE_(("", "....trylock mutex")); - rc = pj_mutex_trylock(mutex); - if (rc == PJ_SUCCESS) - PJ_LOG(3,("", "...info: looks like simple mutex is recursive")); - - /* Unlock and done. */ - TRACE_(("", "....unlock mutex")); - rc = pj_mutex_unlock(mutex); - if (rc != PJ_SUCCESS) return -50; - - TRACE_(("", "....destroy mutex")); - rc = pj_mutex_destroy(mutex); - if (rc != PJ_SUCCESS) return -60; - - TRACE_(("", "....done")); - return PJ_SUCCESS; -} - - -/* Test with recursive mutex. */ -static int recursive_mutex_test(pj_pool_t *pool) -{ - pj_status_t rc; - pj_mutex_t *mutex; - - PJ_LOG(3,("", "...testing recursive mutex")); - - /* Create mutex. */ - TRACE_(("", "....create mutex")); - rc = pj_mutex_create( pool, "", PJ_MUTEX_RECURSE, &mutex); - if (rc != PJ_SUCCESS) { - app_perror("...error: pj_mutex_create", rc); - return -10; - } - - /* Normal lock/unlock cycle. */ - TRACE_(("", "....lock mutex")); - rc = pj_mutex_lock(mutex); - if (rc != PJ_SUCCESS) { - app_perror("...error: pj_mutex_lock", rc); - return -20; - } - TRACE_(("", "....unlock mutex")); - rc = pj_mutex_unlock(mutex); - if (rc != PJ_SUCCESS) { - app_perror("...error: pj_mutex_unlock", rc); - return -30; - } - - /* Lock again. */ - TRACE_(("", "....lock mutex")); - rc = pj_mutex_lock(mutex); - if (rc != PJ_SUCCESS) return -40; - - /* Try-lock should NOT fail. . */ - TRACE_(("", "....trylock mutex")); - rc = pj_mutex_trylock(mutex); - if (rc != PJ_SUCCESS) { - app_perror("...error: recursive mutex is not recursive!", rc); - return -40; - } - - /* Locking again should not fail. */ - TRACE_(("", "....lock mutex")); - rc = pj_mutex_lock(mutex); - if (rc != PJ_SUCCESS) { - app_perror("...error: recursive mutex is not recursive!", rc); - return -45; - } - - /* Unlock several times and done. */ - TRACE_(("", "....unlock mutex 3x")); - rc = pj_mutex_unlock(mutex); - if (rc != PJ_SUCCESS) return -50; - rc = pj_mutex_unlock(mutex); - if (rc != PJ_SUCCESS) return -51; - rc = pj_mutex_unlock(mutex); - if (rc != PJ_SUCCESS) return -52; - - TRACE_(("", "....destroy mutex")); - rc = pj_mutex_destroy(mutex); - if (rc != PJ_SUCCESS) return -60; - - TRACE_(("", "....done")); - return PJ_SUCCESS; -} - -int mutex_test(void) -{ - pj_pool_t *pool; - int rc; - - pool = pj_pool_create(mem, "", 4000, 4000, NULL); - - rc = simple_mutex_test(pool); - if (rc != 0) - return rc; - - rc = recursive_mutex_test(pool); - if (rc != 0) - return rc; - - pj_pool_release(pool); - - return 0; -} - -#else -int dummy_mutex_test; -#endif - +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/mutex.c 1 10/23/05 12:52p Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pjlib-test/mutex.c $ + * + * 1 10/23/05 12:52p Bennylp + * Craeted. + * + */ +#include "test.h" +#include + +#if INCLUDE_MUTEX_TEST + +#undef TRACE_ +//#define TRACE_(x) PJ_LOG(3,x) +#define TRACE_(x) + +/* Test witn non-recursive mutex. */ +static int simple_mutex_test(pj_pool_t *pool) +{ + pj_status_t rc; + pj_mutex_t *mutex; + + PJ_LOG(3,("", "...testing simple mutex")); + + /* Create mutex. */ + TRACE_(("", "....create mutex")); + rc = pj_mutex_create( pool, "", PJ_MUTEX_SIMPLE, &mutex); + if (rc != PJ_SUCCESS) { + app_perror("...error: pj_mutex_create", rc); + return -10; + } + + /* Normal lock/unlock cycle. */ + TRACE_(("", "....lock mutex")); + rc = pj_mutex_lock(mutex); + if (rc != PJ_SUCCESS) { + app_perror("...error: pj_mutex_lock", rc); + return -20; + } + TRACE_(("", "....unlock mutex")); + rc = pj_mutex_unlock(mutex); + if (rc != PJ_SUCCESS) { + app_perror("...error: pj_mutex_unlock", rc); + return -30; + } + + /* Lock again. */ + TRACE_(("", "....lock mutex")); + rc = pj_mutex_lock(mutex); + if (rc != PJ_SUCCESS) return -40; + + /* Try-lock should fail. It should not deadlocked. */ + TRACE_(("", "....trylock mutex")); + rc = pj_mutex_trylock(mutex); + if (rc == PJ_SUCCESS) + PJ_LOG(3,("", "...info: looks like simple mutex is recursive")); + + /* Unlock and done. */ + TRACE_(("", "....unlock mutex")); + rc = pj_mutex_unlock(mutex); + if (rc != PJ_SUCCESS) return -50; + + TRACE_(("", "....destroy mutex")); + rc = pj_mutex_destroy(mutex); + if (rc != PJ_SUCCESS) return -60; + + TRACE_(("", "....done")); + return PJ_SUCCESS; +} + + +/* Test with recursive mutex. */ +static int recursive_mutex_test(pj_pool_t *pool) +{ + pj_status_t rc; + pj_mutex_t *mutex; + + PJ_LOG(3,("", "...testing recursive mutex")); + + /* Create mutex. */ + TRACE_(("", "....create mutex")); + rc = pj_mutex_create( pool, "", PJ_MUTEX_RECURSE, &mutex); + if (rc != PJ_SUCCESS) { + app_perror("...error: pj_mutex_create", rc); + return -10; + } + + /* Normal lock/unlock cycle. */ + TRACE_(("", "....lock mutex")); + rc = pj_mutex_lock(mutex); + if (rc != PJ_SUCCESS) { + app_perror("...error: pj_mutex_lock", rc); + return -20; + } + TRACE_(("", "....unlock mutex")); + rc = pj_mutex_unlock(mutex); + if (rc != PJ_SUCCESS) { + app_perror("...error: pj_mutex_unlock", rc); + return -30; + } + + /* Lock again. */ + TRACE_(("", "....lock mutex")); + rc = pj_mutex_lock(mutex); + if (rc != PJ_SUCCESS) return -40; + + /* Try-lock should NOT fail. . */ + TRACE_(("", "....trylock mutex")); + rc = pj_mutex_trylock(mutex); + if (rc != PJ_SUCCESS) { + app_perror("...error: recursive mutex is not recursive!", rc); + return -40; + } + + /* Locking again should not fail. */ + TRACE_(("", "....lock mutex")); + rc = pj_mutex_lock(mutex); + if (rc != PJ_SUCCESS) { + app_perror("...error: recursive mutex is not recursive!", rc); + return -45; + } + + /* Unlock several times and done. */ + TRACE_(("", "....unlock mutex 3x")); + rc = pj_mutex_unlock(mutex); + if (rc != PJ_SUCCESS) return -50; + rc = pj_mutex_unlock(mutex); + if (rc != PJ_SUCCESS) return -51; + rc = pj_mutex_unlock(mutex); + if (rc != PJ_SUCCESS) return -52; + + TRACE_(("", "....destroy mutex")); + rc = pj_mutex_destroy(mutex); + if (rc != PJ_SUCCESS) return -60; + + TRACE_(("", "....done")); + return PJ_SUCCESS; +} + +int mutex_test(void) +{ + pj_pool_t *pool; + int rc; + + pool = pj_pool_create(mem, "", 4000, 4000, NULL); + + rc = simple_mutex_test(pool); + if (rc != 0) + return rc; + + rc = recursive_mutex_test(pool); + if (rc != 0) + return rc; + + pj_pool_release(pool); + + return 0; +} + +#else +int dummy_mutex_test; +#endif + diff --git a/pjlib/src/pjlib-test/os.c b/pjlib/src/pjlib-test/os.c index 893cfc69..6f35c7de 100644 --- a/pjlib/src/pjlib-test/os.c +++ b/pjlib/src/pjlib-test/os.c @@ -1,10 +1,10 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/os.c 2 10/14/05 12:26a Bennylp $ - */ -/* - * $Log: /pjproject-0.3/pjlib/src/pjlib-test/os.c $ - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - */ +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/os.c 2 10/14/05 12:26a Bennylp $ + */ +/* + * $Log: /pjproject-0.3/pjlib/src/pjlib-test/os.c $ + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + */ diff --git a/pjlib/src/pjlib-test/pool.c b/pjlib/src/pjlib-test/pool.c index 8b9d1ff0..26d8e01f 100644 --- a/pjlib/src/pjlib-test/pool.c +++ b/pjlib/src/pjlib-test/pool.c @@ -1,164 +1,164 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/pool.c 2 10/14/05 12:26a Bennylp $ - */ -/* - * $Log: /pjproject-0.3/pjlib/src/pjlib-test/pool.c $ - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - */ -#include -#include -#include -#include "test.h" - -/** - * \page page_pjlib_pool_test Test: Pool - * - * This file provides implementation of \b pool_test(). It tests the - * functionality of the memory pool. - * - * - * This file is pjlib-test/pool.c - * - * \include pjlib-test/pool.c - */ - - -#if INCLUDE_POOL_TEST - -#define SIZE 4096 - -/* Normally we should throw exception when memory alloc fails. - * Here we do nothing so that the flow will go back to original caller, - * which will test the result using NULL comparison. Normally caller will - * catch the exception instead of checking for NULLs. - */ -static void null_callback(pj_pool_t *pool, pj_size_t size) -{ - PJ_UNUSED_ARG(pool); - PJ_UNUSED_ARG(size); -} - -#define GET_FREE(p) (pj_pool_get_capacity(p)-pj_pool_get_used_size(p)) - -/* Test that the capacity and used size reported by the pool is correct. - */ -static int capacity_test(void) -{ - pj_pool_t *pool = pj_pool_create(mem, NULL, SIZE, 0, &null_callback); - pj_size_t freesize; - - PJ_LOG(3,("test", "...capacity_test()")); - - if (!pool) - return -200; - - freesize = GET_FREE(pool); - - if (pj_pool_alloc(pool, freesize) == NULL) { - PJ_LOG(3,("test", "...error: wrong freesize %u reported", - freesize)); - pj_pool_release(pool); - return -210; - } - - pj_pool_release(pool); - return 0; -} - -/* Test function to drain the pool's space. - */ -static int drain_test(pj_size_t size, pj_size_t increment) -{ - pj_pool_t *pool = pj_pool_create(mem, NULL, size, increment, - &null_callback); - pj_size_t freesize; - void *p; - int status = 0; - - PJ_LOG(3,("test", "...drain_test(%d,%d)", size, increment)); - - if (!pool) - return -10; - - /* Get free size */ - freesize = GET_FREE(pool); - if (freesize < 1) { - status=-15; - goto on_error; - } - - /* Drain the pool until there's nothing left. */ - while (freesize > 0) { - int size; - - if (freesize > 255) - size = ((pj_rand() & 0x000000FF) + 4) & ~0x03L; - else - size = freesize; - - p = pj_pool_alloc(pool, size); - if (!p) { - status=-20; goto on_error; - } - - freesize -= size; - } - - /* Check that capacity is zero. */ - if (GET_FREE(pool) != 0) { - PJ_LOG(3,("test", "....error: returned free=%u (expecting 0)", - GET_FREE(pool))); - status=-30; goto on_error; - } - - /* Try to allocate once more */ - p = pj_pool_alloc(pool, 257); - if (!p) { - status=-40; goto on_error; - } - - /* Check that capacity is NOT zero. */ - if (GET_FREE(pool) == 0) { - status=-50; goto on_error; - } - - -on_error: - pj_pool_release(pool); - return status; -} - -int pool_test(void) -{ - enum { LOOP = 2 }; - int loop; - int rc; - - rc = capacity_test(); - if (rc) return rc; - - for (loop=0; loop +#include +#include +#include "test.h" + +/** + * \page page_pjlib_pool_test Test: Pool + * + * This file provides implementation of \b pool_test(). It tests the + * functionality of the memory pool. + * + * + * This file is pjlib-test/pool.c + * + * \include pjlib-test/pool.c + */ + + +#if INCLUDE_POOL_TEST + +#define SIZE 4096 + +/* Normally we should throw exception when memory alloc fails. + * Here we do nothing so that the flow will go back to original caller, + * which will test the result using NULL comparison. Normally caller will + * catch the exception instead of checking for NULLs. + */ +static void null_callback(pj_pool_t *pool, pj_size_t size) +{ + PJ_UNUSED_ARG(pool); + PJ_UNUSED_ARG(size); +} + +#define GET_FREE(p) (pj_pool_get_capacity(p)-pj_pool_get_used_size(p)) + +/* Test that the capacity and used size reported by the pool is correct. + */ +static int capacity_test(void) +{ + pj_pool_t *pool = pj_pool_create(mem, NULL, SIZE, 0, &null_callback); + pj_size_t freesize; + + PJ_LOG(3,("test", "...capacity_test()")); + + if (!pool) + return -200; + + freesize = GET_FREE(pool); + + if (pj_pool_alloc(pool, freesize) == NULL) { + PJ_LOG(3,("test", "...error: wrong freesize %u reported", + freesize)); + pj_pool_release(pool); + return -210; + } + + pj_pool_release(pool); + return 0; +} + +/* Test function to drain the pool's space. + */ +static int drain_test(pj_size_t size, pj_size_t increment) +{ + pj_pool_t *pool = pj_pool_create(mem, NULL, size, increment, + &null_callback); + pj_size_t freesize; + void *p; + int status = 0; + + PJ_LOG(3,("test", "...drain_test(%d,%d)", size, increment)); + + if (!pool) + return -10; + + /* Get free size */ + freesize = GET_FREE(pool); + if (freesize < 1) { + status=-15; + goto on_error; + } + + /* Drain the pool until there's nothing left. */ + while (freesize > 0) { + int size; + + if (freesize > 255) + size = ((pj_rand() & 0x000000FF) + 4) & ~0x03L; + else + size = freesize; + + p = pj_pool_alloc(pool, size); + if (!p) { + status=-20; goto on_error; + } + + freesize -= size; + } + + /* Check that capacity is zero. */ + if (GET_FREE(pool) != 0) { + PJ_LOG(3,("test", "....error: returned free=%u (expecting 0)", + GET_FREE(pool))); + status=-30; goto on_error; + } + + /* Try to allocate once more */ + p = pj_pool_alloc(pool, 257); + if (!p) { + status=-40; goto on_error; + } + + /* Check that capacity is NOT zero. */ + if (GET_FREE(pool) == 0) { + status=-50; goto on_error; + } + + +on_error: + pj_pool_release(pool); + return status; +} + +int pool_test(void) +{ + enum { LOOP = 2 }; + int loop; + int rc; + + rc = capacity_test(); + if (rc) return rc; + + for (loop=0; loop -#include - -#if !PJ_HAS_HIGH_RES_TIMER -# error Need high resolution timer for this test. -#endif - -#define THIS_FILE "test" - -#define LOOP 10 -#define COUNT 1024 -static unsigned sizes[COUNT]; -#define MIN_SIZE 4 -#define MAX_SIZE 512 -static unsigned total_size; - -static int pool_test_pool() -{ - int i; - pj_pool_t *pool = pj_pool_create(mem, NULL, total_size + 4*COUNT, 0, NULL); - if (!pool) - return -1; - - for (i=0; i +#include + +#if !PJ_HAS_HIGH_RES_TIMER +# error Need high resolution timer for this test. +#endif + +#define THIS_FILE "test" + +#define LOOP 10 +#define COUNT 1024 +static unsigned sizes[COUNT]; +#define MIN_SIZE 4 +#define MAX_SIZE 512 +static unsigned total_size; + +static int pool_test_pool() +{ + int i; + pj_pool_t *pool = pj_pool_create(mem, NULL, total_size + 4*COUNT, 0, NULL); + if (!pool) + return -1; + + for (i=0; i -#include -#include "test.h" - -#if INCLUDE_RAND_TEST - -#define COUNT 1024 -static int values[COUNT]; - -/* - * rand_test(), simply generates COUNT number of random number and - * check that there's no duplicate numbers. - */ -int rand_test(void) -{ - int i; - - for (i=0; i +#include +#include "test.h" + +#if INCLUDE_RAND_TEST + +#define COUNT 1024 +static int values[COUNT]; + +/* + * rand_test(), simply generates COUNT number of random number and + * check that there's no duplicate numbers. + */ +int rand_test(void) +{ + int i; + + for (i=0; i - -#define LOOP 32 -#define MIN_COUNT 64 -#define MAX_COUNT (LOOP * MIN_COUNT) -#define STRSIZE 16 -#define THIS_FILE "rbtree_test" - -typedef struct node_key -{ - pj_uint32_t hash; - char str[STRSIZE]; -} node_key; - -static int compare_node(const node_key *k1, const node_key *k2) -{ - if (k1->hash == k2->hash) { - return strcmp(k1->str, k2->str); - } else { - return k1->hash < k2->hash ? -1 : 1; - } -} - -void randomize_string(char *str, int len) -{ - int i; - for (i=0; ikey,(node_key*)it->key)>=0) { - ++err; - PJ_LOG(3, (THIS_FILE, "Error: %s >= %s", - (char*)prev->user_data, (char*)it->user_data)); - } - } - prev = it; - it = pj_rbtree_next(&rb, it); - } - - // Search. - for (j=0; j MAX_COUNT) - break; - } - - pj_pool_release(pool); - return err; -} - - -int rbtree_test() -{ - return test(); -} - -#endif /* INCLUDE_RBTREE_TEST */ - - +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/rbtree.c 2 10/14/05 12:26a Bennylp $ */ +#include "test.h" + +#if INCLUDE_RBTREE_TEST + +#include + +#define LOOP 32 +#define MIN_COUNT 64 +#define MAX_COUNT (LOOP * MIN_COUNT) +#define STRSIZE 16 +#define THIS_FILE "rbtree_test" + +typedef struct node_key +{ + pj_uint32_t hash; + char str[STRSIZE]; +} node_key; + +static int compare_node(const node_key *k1, const node_key *k2) +{ + if (k1->hash == k2->hash) { + return strcmp(k1->str, k2->str); + } else { + return k1->hash < k2->hash ? -1 : 1; + } +} + +void randomize_string(char *str, int len) +{ + int i; + for (i=0; ikey,(node_key*)it->key)>=0) { + ++err; + PJ_LOG(3, (THIS_FILE, "Error: %s >= %s", + (char*)prev->user_data, (char*)it->user_data)); + } + } + prev = it; + it = pj_rbtree_next(&rb, it); + } + + // Search. + for (j=0; j MAX_COUNT) + break; + } + + pj_pool_release(pool); + return err; +} + + +int rbtree_test() +{ + return test(); +} + +#endif /* INCLUDE_RBTREE_TEST */ + + diff --git a/pjlib/src/pjlib-test/select.c b/pjlib/src/pjlib-test/select.c index e6562d2c..eaaffcc5 100644 --- a/pjlib/src/pjlib-test/select.c +++ b/pjlib/src/pjlib-test/select.c @@ -1,208 +1,208 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/select.c 2 10/14/05 12:26a Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pjlib-test/select.c $ - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - */ -#include "test.h" - -/** - * \page page_pjlib_select_test Test: Socket Select() - * - * This file provides implementation of \b select_test(). It tests the - * functionality of the pj_sock_select() API. - * - * - * This file is pjlib-test/select.c - * - * \include pjlib-test/select.c - */ - - -#if INCLUDE_SELECT_TEST - -#include -#include -#include -#include -#include -#include -#include - -enum -{ - READ_FDS, - WRITE_FDS, - EXCEPT_FDS -}; - -#define UDP_PORT 51232 -#define THIS_FILE "select_test" - -/* - * do_select() - * - * Perform pj_sock_select() and find out which sockets - * are signalled. - */ -static int do_select( pj_sock_t sock1, pj_sock_t sock2, - int setcount[]) -{ - pj_fd_set_t fds[3]; - pj_time_val timeout; - int i, n; - - for (i=0; i<3; ++i) { - PJ_FD_ZERO(&fds[i]); - PJ_FD_SET(sock1, &fds[i]); - PJ_FD_SET(sock2, &fds[i]); - setcount[i] = 0; - } - - timeout.sec = 1; - timeout.msec = 0; - - n = pj_sock_select(FD_SETSIZE, &fds[0], &fds[1], &fds[2], - &timeout); - if (n < 0) - return n; - if (n == 0) - return 0; - - for (i=0; i<3; ++i) { - if (PJ_FD_ISSET(sock1, &fds[i])) - setcount[i]++; - if (PJ_FD_ISSET(sock2, &fds[i])) - setcount[i]++; - } - - return n; -} - -/* - * select_test() - * - * Test main entry. - */ -int select_test() -{ - pj_sock_t udp1=PJ_INVALID_SOCKET, udp2=PJ_INVALID_SOCKET; - pj_sockaddr_in udp_addr; - int status; - int setcount[3]; - pj_str_t s; - const char data[] = "hello"; - const int datalen = 5; - pj_ssize_t sent, received; - char buf[10]; - pj_status_t rc; - - PJ_LOG(3, (THIS_FILE, "...Testing simple UDP select()")); - - // Create two UDP sockets. - rc = pj_sock_socket( PJ_AF_INET, PJ_SOCK_DGRAM, 0, &udp1); - if (rc != PJ_SUCCESS) { - app_perror("...error: unable to create socket", rc); - status=-10; goto on_return; - } - rc = pj_sock_socket( PJ_AF_INET, PJ_SOCK_DGRAM, 0, &udp2); - if (udp2 == PJ_INVALID_SOCKET) { - app_perror("...error: unable to create socket", rc); - status=-20; goto on_return; - } - - // Bind one of the UDP socket. - pj_memset(&udp_addr, 0, sizeof(udp_addr)); - udp_addr.sin_family = PJ_AF_INET; - udp_addr.sin_port = UDP_PORT; - udp_addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1")); - - if (pj_sock_bind(udp2, &udp_addr, sizeof(udp_addr))) { - status=-30; goto on_return; - } - - // Send data. - sent = datalen; - rc = pj_sock_sendto(udp1, data, &sent, 0, &udp_addr, sizeof(udp_addr)); - if (rc != PJ_SUCCESS || sent != datalen) { - app_perror("...error: sendto() error", rc); - status=-40; goto on_return; - } - - // Check that socket is marked as reable. - // Note that select() may also report that sockets are writable. - status = do_select(udp1, udp2, setcount); - if (status < 0) { - char errbuf[128]; - pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf)); - PJ_LOG(1,(THIS_FILE, "...error: %s", errbuf)); - status=-50; goto on_return; - } - if (status == 0) { - status=-60; goto on_return; - } - - if (setcount[READ_FDS] != 1) { - status=-70; goto on_return; - } - if (setcount[WRITE_FDS] != 0) { - if (setcount[WRITE_FDS] == 2) { - PJ_LOG(3,(THIS_FILE, "...info: system reports writable sockets")); - } else { - status=-80; goto on_return; - } - } else { - PJ_LOG(3,(THIS_FILE, - "...info: system doesn't report writable sockets")); - } - if (setcount[EXCEPT_FDS] != 0) { - status=-90; goto on_return; - } - - // Read the socket to clear readable sockets. - received = sizeof(buf); - rc = pj_sock_recv(udp2, buf, &received, 0); - if (rc != PJ_SUCCESS || received != 5) { - status=-100; goto on_return; - } - - status = 0; - - // Test timeout on the read part. - // This won't necessarily return zero, as select() may report that - // sockets are writable. - setcount[0] = setcount[1] = setcount[2] = 0; - status = do_select(udp1, udp2, setcount); - if (status != 0 && status != setcount[WRITE_FDS]) { - PJ_LOG(3,(THIS_FILE, "...error: expecting timeout but got %d sks set", - status)); - PJ_LOG(3,(THIS_FILE, " rdset: %d, wrset: %d, exset: %d", - setcount[0], setcount[1], setcount[2])); - status = -110; goto on_return; - } - if (setcount[READ_FDS] != 0) { - PJ_LOG(3,(THIS_FILE, "...error: readable socket not expected")); - status = -120; goto on_return; - } - - status = 0; - -on_return: - if (udp1 != PJ_INVALID_SOCKET) - pj_sock_close(udp1); - if (udp2 != PJ_INVALID_SOCKET) - pj_sock_close(udp2); - return status; -} - -#else -/* To prevent warning about "translation unit is empty" - * when this test is disabled. - */ -int dummy_select_test; -#endif /* INCLUDE_SELECT_TEST */ - - +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/select.c 2 10/14/05 12:26a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pjlib-test/select.c $ + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + */ +#include "test.h" + +/** + * \page page_pjlib_select_test Test: Socket Select() + * + * This file provides implementation of \b select_test(). It tests the + * functionality of the pj_sock_select() API. + * + * + * This file is pjlib-test/select.c + * + * \include pjlib-test/select.c + */ + + +#if INCLUDE_SELECT_TEST + +#include +#include +#include +#include +#include +#include +#include + +enum +{ + READ_FDS, + WRITE_FDS, + EXCEPT_FDS +}; + +#define UDP_PORT 51232 +#define THIS_FILE "select_test" + +/* + * do_select() + * + * Perform pj_sock_select() and find out which sockets + * are signalled. + */ +static int do_select( pj_sock_t sock1, pj_sock_t sock2, + int setcount[]) +{ + pj_fd_set_t fds[3]; + pj_time_val timeout; + int i, n; + + for (i=0; i<3; ++i) { + PJ_FD_ZERO(&fds[i]); + PJ_FD_SET(sock1, &fds[i]); + PJ_FD_SET(sock2, &fds[i]); + setcount[i] = 0; + } + + timeout.sec = 1; + timeout.msec = 0; + + n = pj_sock_select(FD_SETSIZE, &fds[0], &fds[1], &fds[2], + &timeout); + if (n < 0) + return n; + if (n == 0) + return 0; + + for (i=0; i<3; ++i) { + if (PJ_FD_ISSET(sock1, &fds[i])) + setcount[i]++; + if (PJ_FD_ISSET(sock2, &fds[i])) + setcount[i]++; + } + + return n; +} + +/* + * select_test() + * + * Test main entry. + */ +int select_test() +{ + pj_sock_t udp1=PJ_INVALID_SOCKET, udp2=PJ_INVALID_SOCKET; + pj_sockaddr_in udp_addr; + int status; + int setcount[3]; + pj_str_t s; + const char data[] = "hello"; + const int datalen = 5; + pj_ssize_t sent, received; + char buf[10]; + pj_status_t rc; + + PJ_LOG(3, (THIS_FILE, "...Testing simple UDP select()")); + + // Create two UDP sockets. + rc = pj_sock_socket( PJ_AF_INET, PJ_SOCK_DGRAM, 0, &udp1); + if (rc != PJ_SUCCESS) { + app_perror("...error: unable to create socket", rc); + status=-10; goto on_return; + } + rc = pj_sock_socket( PJ_AF_INET, PJ_SOCK_DGRAM, 0, &udp2); + if (udp2 == PJ_INVALID_SOCKET) { + app_perror("...error: unable to create socket", rc); + status=-20; goto on_return; + } + + // Bind one of the UDP socket. + pj_memset(&udp_addr, 0, sizeof(udp_addr)); + udp_addr.sin_family = PJ_AF_INET; + udp_addr.sin_port = UDP_PORT; + udp_addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1")); + + if (pj_sock_bind(udp2, &udp_addr, sizeof(udp_addr))) { + status=-30; goto on_return; + } + + // Send data. + sent = datalen; + rc = pj_sock_sendto(udp1, data, &sent, 0, &udp_addr, sizeof(udp_addr)); + if (rc != PJ_SUCCESS || sent != datalen) { + app_perror("...error: sendto() error", rc); + status=-40; goto on_return; + } + + // Check that socket is marked as reable. + // Note that select() may also report that sockets are writable. + status = do_select(udp1, udp2, setcount); + if (status < 0) { + char errbuf[128]; + pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf)); + PJ_LOG(1,(THIS_FILE, "...error: %s", errbuf)); + status=-50; goto on_return; + } + if (status == 0) { + status=-60; goto on_return; + } + + if (setcount[READ_FDS] != 1) { + status=-70; goto on_return; + } + if (setcount[WRITE_FDS] != 0) { + if (setcount[WRITE_FDS] == 2) { + PJ_LOG(3,(THIS_FILE, "...info: system reports writable sockets")); + } else { + status=-80; goto on_return; + } + } else { + PJ_LOG(3,(THIS_FILE, + "...info: system doesn't report writable sockets")); + } + if (setcount[EXCEPT_FDS] != 0) { + status=-90; goto on_return; + } + + // Read the socket to clear readable sockets. + received = sizeof(buf); + rc = pj_sock_recv(udp2, buf, &received, 0); + if (rc != PJ_SUCCESS || received != 5) { + status=-100; goto on_return; + } + + status = 0; + + // Test timeout on the read part. + // This won't necessarily return zero, as select() may report that + // sockets are writable. + setcount[0] = setcount[1] = setcount[2] = 0; + status = do_select(udp1, udp2, setcount); + if (status != 0 && status != setcount[WRITE_FDS]) { + PJ_LOG(3,(THIS_FILE, "...error: expecting timeout but got %d sks set", + status)); + PJ_LOG(3,(THIS_FILE, " rdset: %d, wrset: %d, exset: %d", + setcount[0], setcount[1], setcount[2])); + status = -110; goto on_return; + } + if (setcount[READ_FDS] != 0) { + PJ_LOG(3,(THIS_FILE, "...error: readable socket not expected")); + status = -120; goto on_return; + } + + status = 0; + +on_return: + if (udp1 != PJ_INVALID_SOCKET) + pj_sock_close(udp1); + if (udp2 != PJ_INVALID_SOCKET) + pj_sock_close(udp2); + return status; +} + +#else +/* To prevent warning about "translation unit is empty" + * when this test is disabled. + */ +int dummy_select_test; +#endif /* INCLUDE_SELECT_TEST */ + + diff --git a/pjlib/src/pjlib-test/sleep.c b/pjlib/src/pjlib-test/sleep.c index 95fa3bac..cb33104f 100644 --- a/pjlib/src/pjlib-test/sleep.c +++ b/pjlib/src/pjlib-test/sleep.c @@ -1,198 +1,198 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/sleep.c 3 10/29/05 11:51a Bennylp $ - */ -/* - * $Log: /pjproject-0.3/pjlib/src/pjlib-test/sleep.c $ - * - * 3 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 10/11/05 12:53a Bennylp - * Created. - * - */ -#include "test.h" - -/** - * \page page_pjlib_sleep_test Test: Sleep, Time, and Timestamp - * - * This file provides implementation of \b sleep_test(). - * - * \section sleep_test_sec Scope of the Test - * - * This tests: - * - whether pj_thread_sleep() works. - * - whether pj_gettimeofday() works. - * - whether pj_get_timestamp() and friends works. - * - * API tested: - * - pj_thread_sleep() - * - pj_gettimeofday() - * - PJ_TIME_VAL_SUB() - * - PJ_TIME_VAL_LTE() - * - pj_get_timestamp() - * - pj_get_timestamp_freq() (implicitly) - * - pj_elapsed_time() - * - pj_elapsed_usec() - * - * - * This file is pjlib-test/sleep.c - * - * \include pjlib-test/sleep.c - */ - -#if INCLUDE_SLEEP_TEST - -#include - -#define THIS_FILE "sleep_test" - -static int simple_sleep_test(void) -{ - enum { COUNT = 5 }; - int i; - pj_status_t rc; - - PJ_LOG(3,(THIS_FILE, "..will write messages every 1 second:")); - - for (i=0; i DURATION * (100+MIS)/100) - { - PJ_LOG(3,(THIS_FILE, - "...error: slept for %d ms instead of %d ms " - "(outside %d%% err window)", - msec, DURATION, MIS)); - return -30; - } - } - - - /* Test pj_thread_sleep() and pj_get_timestamp() and friends */ - { - pj_time_val t1, t2; - pj_timestamp start, stop; - pj_time_val elapsed; - pj_uint32_t msec; - - /* Mark start of test. */ - rc = pj_get_timestamp(&start); - if (rc != PJ_SUCCESS) { - app_perror("...error: pj_get_timestamp()", rc); - return -60; - } - - /* ..also with gettimeofday() */ - pj_gettimeofday(&t1); - - /* Sleep */ - rc = pj_thread_sleep(DURATION2); - if (rc != PJ_SUCCESS) { - app_perror("...error: pj_thread_sleep()", rc); - return -70; - } - - /* Mark end of test. */ - pj_get_timestamp(&stop); - - /* ..also with gettimeofday() */ - pj_gettimeofday(&t2); - - /* Compare t1 and t2. */ - if (PJ_TIME_VAL_LTE(t2, t1)) { - PJ_LOG(3,(THIS_FILE, "...error: t2 is less than t1!!")); - return -75; - } - - /* Get elapsed time in time_val */ - elapsed = pj_elapsed_time(&start, &stop); - - msec = PJ_TIME_VAL_MSEC(elapsed); - - /* Check if it's within range. */ - if (msec < DURATION2 * (100-MIS)/100 || - msec > DURATION2 * (100+MIS)/100) - { - PJ_LOG(3,(THIS_FILE, - "...error: slept for %d ms instead of %d ms " - "(outside %d%% err window)", - msec, DURATION2, MIS)); - return -30; - } - } - - /* All done. */ - return 0; -} - -int sleep_test() -{ - int rc; - - rc = simple_sleep_test(); - if (rc != PJ_SUCCESS) - return rc; - - rc = sleep_duration_test(); - if (rc != PJ_SUCCESS) - return rc; - - return 0; -} - -#else -/* To prevent warning about "translation unit is empty" - * when this test is disabled. - */ -int dummy_sleep_test; -#endif /* INCLUDE_SLEEP_TEST */ +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/sleep.c 3 10/29/05 11:51a Bennylp $ + */ +/* + * $Log: /pjproject-0.3/pjlib/src/pjlib-test/sleep.c $ + * + * 3 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 10/11/05 12:53a Bennylp + * Created. + * + */ +#include "test.h" + +/** + * \page page_pjlib_sleep_test Test: Sleep, Time, and Timestamp + * + * This file provides implementation of \b sleep_test(). + * + * \section sleep_test_sec Scope of the Test + * + * This tests: + * - whether pj_thread_sleep() works. + * - whether pj_gettimeofday() works. + * - whether pj_get_timestamp() and friends works. + * + * API tested: + * - pj_thread_sleep() + * - pj_gettimeofday() + * - PJ_TIME_VAL_SUB() + * - PJ_TIME_VAL_LTE() + * - pj_get_timestamp() + * - pj_get_timestamp_freq() (implicitly) + * - pj_elapsed_time() + * - pj_elapsed_usec() + * + * + * This file is pjlib-test/sleep.c + * + * \include pjlib-test/sleep.c + */ + +#if INCLUDE_SLEEP_TEST + +#include + +#define THIS_FILE "sleep_test" + +static int simple_sleep_test(void) +{ + enum { COUNT = 5 }; + int i; + pj_status_t rc; + + PJ_LOG(3,(THIS_FILE, "..will write messages every 1 second:")); + + for (i=0; i DURATION * (100+MIS)/100) + { + PJ_LOG(3,(THIS_FILE, + "...error: slept for %d ms instead of %d ms " + "(outside %d%% err window)", + msec, DURATION, MIS)); + return -30; + } + } + + + /* Test pj_thread_sleep() and pj_get_timestamp() and friends */ + { + pj_time_val t1, t2; + pj_timestamp start, stop; + pj_time_val elapsed; + pj_uint32_t msec; + + /* Mark start of test. */ + rc = pj_get_timestamp(&start); + if (rc != PJ_SUCCESS) { + app_perror("...error: pj_get_timestamp()", rc); + return -60; + } + + /* ..also with gettimeofday() */ + pj_gettimeofday(&t1); + + /* Sleep */ + rc = pj_thread_sleep(DURATION2); + if (rc != PJ_SUCCESS) { + app_perror("...error: pj_thread_sleep()", rc); + return -70; + } + + /* Mark end of test. */ + pj_get_timestamp(&stop); + + /* ..also with gettimeofday() */ + pj_gettimeofday(&t2); + + /* Compare t1 and t2. */ + if (PJ_TIME_VAL_LTE(t2, t1)) { + PJ_LOG(3,(THIS_FILE, "...error: t2 is less than t1!!")); + return -75; + } + + /* Get elapsed time in time_val */ + elapsed = pj_elapsed_time(&start, &stop); + + msec = PJ_TIME_VAL_MSEC(elapsed); + + /* Check if it's within range. */ + if (msec < DURATION2 * (100-MIS)/100 || + msec > DURATION2 * (100+MIS)/100) + { + PJ_LOG(3,(THIS_FILE, + "...error: slept for %d ms instead of %d ms " + "(outside %d%% err window)", + msec, DURATION2, MIS)); + return -30; + } + } + + /* All done. */ + return 0; +} + +int sleep_test() +{ + int rc; + + rc = simple_sleep_test(); + if (rc != PJ_SUCCESS) + return rc; + + rc = sleep_duration_test(); + if (rc != PJ_SUCCESS) + return rc; + + return 0; +} + +#else +/* To prevent warning about "translation unit is empty" + * when this test is disabled. + */ +int dummy_sleep_test; +#endif /* INCLUDE_SLEEP_TEST */ diff --git a/pjlib/src/pjlib-test/sock.c b/pjlib/src/pjlib-test/sock.c index 9135a8bb..c50c15cb 100644 --- a/pjlib/src/pjlib-test/sock.c +++ b/pjlib/src/pjlib-test/sock.c @@ -1,459 +1,459 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/sock.c 4 10/29/05 11:51a Bennylp $ */ -/* $Log: /pjproject-0.3/pjlib/src/pjlib-test/sock.c $ - * - * 4 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 3 14/10/05 11:31 Bennylp - * Fixed bug when TCP data is received in chunks. - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 9/21/05 1:38p Bennylp - * Renamed from *.cpp - * - * 2 9/17/05 10:37a Bennylp - * Major reorganization towards version 0.3. - * - * 1 9/15/05 8:41p Bennylp - */ -#include -#include "test.h" - - -/** - * \page page_pjlib_sock_test Test: Socket - * - * This file provides implementation of \b sock_test(). It tests the - * various aspects of the socket API. - * - * \section sock_test_scope_sec Scope of the Test - * - * The scope of the test: - * - verify the validity of the address structs. - * - verify that address manipulation API works. - * - simple socket creation and destruction. - * - simple socket send/recv and sendto/recvfrom. - * - UDP connect() - * - send/recv big data. - * - all for both UDP and TCP. - * - * The APIs tested in this test: - * - pj_inet_aton() - * - pj_inet_ntoa() - * - pj_gethostname() - * - pj_sock_socket() - * - pj_sock_close() - * - pj_sock_send() - * - pj_sock_sendto() - * - pj_sock_recv() - * - pj_sock_recvfrom() - * - pj_sock_bind() - * - pj_sock_connect() - * - pj_sock_listen() - * - pj_sock_accept() - * - * - * This file is pjlib-test/sock.c - * - * \include pjlib-test/sock.c - */ - -#if INCLUDE_SOCK_TEST - -#define UDP_PORT 51234 -#define TCP_PORT (UDP_PORT+10) -#define BIG_DATA_LEN 9000 - -static char bigdata[BIG_DATA_LEN]; -static char bigbuffer[BIG_DATA_LEN]; - -static int format_test(void) -{ - pj_str_t s = pj_str("127.0.0.1"); - char *p; - pj_in_addr addr; - const pj_str_t *hostname; - - PJ_LOG(3,("test", "...format_test()")); - - /* pj_inet_aton() */ - if (pj_inet_aton(&s, &addr) != 1) - return -10; - - /* Check the result. */ - p = (char*)&addr; - if (p[0]!=127 || p[1]!=0 || p[2]!=0 || p[3]!=1) - return -15; - - /* pj_inet_ntoa() */ - p = pj_inet_ntoa(addr); - if (!p) - return -20; - - if (pj_strcmp2(&s, p) != 0) - return -30; - - /* pj_gethostname() */ - hostname = pj_gethostname(); - if (!hostname || !hostname->ptr || !hostname->slen) - return -40; - - /* pj_gethostaddr() */ - - return 0; -} - -static int simple_sock_test(void) -{ - int types[2]; - pj_sock_t sock; - int i; - pj_status_t rc = PJ_SUCCESS; - - types[0] = PJ_SOCK_STREAM; - types[1] = PJ_SOCK_DGRAM; - - PJ_LOG(3,("test", "...simple_sock_test()")); - - for (i=0; isin_addr)); - strcpy(addr_str, pj_inet_ntoa(addr.sin_addr)); - PJ_LOG(3,("test", "...error: src address mismatch (original=%s, " - "recvfrom addr=%s)", - srcaddr_str, addr_str)); - return -152; - } - - } else { - /* Repeat recv() until all data is received. - * This applies only for non-UDP of course, since for UDP - * we would expect all data to be received in one packet. - */ - total_received = 0; - do { - received = DATA_LEN-total_received; - rc = pj_sock_recv(ss, recvdata+total_received, &received, 0); - if (rc != PJ_SUCCESS) { - app_perror("...recv error", rc); - rc = -155; goto on_error; - } - if (received <= 0) { - PJ_LOG(3,("", "...error: socket has closed! (received=%d)", - received)); - rc = -156; goto on_error; - } - if (received != DATA_LEN-total_received) { - if (sock_type != PJ_SOCK_STREAM) { - PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes", - DATA_LEN-total_received, received)); - rc = -157; goto on_error; - } - } - total_received += received; - } while (total_received < DATA_LEN); - } - - TRACE_(("test", "....memcmp()")); - if (pj_memcmp(senddata, recvdata, DATA_LEN) != 0) { - PJ_LOG(3,("","...error: received data mismatch " - "(got:'%s' expecting:'%s'", - recvdata, senddata)); - rc = -160; goto on_error; - } - - /* - * Test send/recv big data. - */ - TRACE_(("test", "....sendto()")); - if (dstaddr) { - sent = BIG_DATA_LEN; - rc = pj_sock_sendto(cs, bigdata, &sent, 0, dstaddr, addrlen); - if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) { - app_perror("...sendto error", rc); - rc = -161; goto on_error; - } - } else { - sent = BIG_DATA_LEN; - rc = pj_sock_send(cs, bigdata, &sent, 0); - if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) { - app_perror("...send error", rc); - rc = -165; goto on_error; - } - } - - TRACE_(("test", "....recv()")); - - /* Repeat recv() until all data is received. - * This applies only for non-UDP of course, since for UDP - * we would expect all data to be received in one packet. - */ - total_received = 0; - do { - received = BIG_DATA_LEN-total_received; - rc = pj_sock_recv(ss, bigbuffer+total_received, &received, 0); - if (rc != PJ_SUCCESS) { - app_perror("...recv error", rc); - rc = -170; goto on_error; - } - if (received <= 0) { - PJ_LOG(3,("", "...error: socket has closed! (received=%d)", - received)); - rc = -173; goto on_error; - } - if (received != BIG_DATA_LEN-total_received) { - if (sock_type != PJ_SOCK_STREAM) { - PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes", - BIG_DATA_LEN-total_received, received)); - rc = -176; goto on_error; - } - } - total_received += received; - } while (total_received < BIG_DATA_LEN); - - TRACE_(("test", "....memcmp()")); - if (pj_memcmp(bigdata, bigbuffer, BIG_DATA_LEN) != 0) { - PJ_LOG(3,("", "...error: received data has been altered!")); - rc = -180; goto on_error; - } - - rc = 0; - -on_error: - return rc; -} - -static int udp_test(void) -{ - pj_sock_t cs = PJ_INVALID_SOCKET, ss = PJ_INVALID_SOCKET; - pj_sockaddr_in dstaddr, srcaddr; - pj_str_t s; - pj_status_t rc = 0, retval; - - PJ_LOG(3,("test", "...udp_test()")); - - rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ss); - if (rc != 0) { - app_perror("...error: unable to create socket", rc); - return -100; - } - - rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &cs); - if (rc != 0) - return -110; - - /* Bind server socket. */ - pj_memset(&dstaddr, 0, sizeof(dstaddr)); - dstaddr.sin_family = PJ_AF_INET; - dstaddr.sin_port = pj_htons(UDP_PORT); - dstaddr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1")); - - if ((rc=pj_sock_bind(ss, &dstaddr, sizeof(dstaddr))) != 0) { - app_perror("...bind error", rc); - rc = -120; goto on_error; - } - - /* Bind client socket. */ - pj_memset(&srcaddr, 0, sizeof(srcaddr)); - srcaddr.sin_family = PJ_AF_INET; - srcaddr.sin_port = pj_htons(UDP_PORT-1); - srcaddr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1")); - - if ((rc=pj_sock_bind(cs, &srcaddr, sizeof(srcaddr))) != 0) { - app_perror("...bind error", rc); - rc = -121; goto on_error; - } - - /* Test send/recv, with sendto */ - rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, &dstaddr, NULL, - sizeof(dstaddr)); - if (rc != 0) - goto on_error; - - /* Test send/recv, with sendto and recvfrom */ - rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, &dstaddr, - &srcaddr, sizeof(dstaddr)); - if (rc != 0) - goto on_error; - - /* connect() the sockets. */ - rc = pj_sock_connect(cs, &dstaddr, sizeof(dstaddr)); - if (rc != 0) { - app_perror("...connect() error", rc); - rc = -122; goto on_error; - } - - /* Test send/recv with send() */ - rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, NULL, NULL, 0); - if (rc != 0) - goto on_error; - - /* Test send/recv with send() and recvfrom */ - rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, NULL, &srcaddr, - sizeof(srcaddr)); - if (rc != 0) - goto on_error; - -on_error: - retval = rc; - if (cs != PJ_INVALID_SOCKET) { - rc = pj_sock_close(cs); - if (rc != PJ_SUCCESS) { - app_perror("...error in closing socket", rc); - return -1000; - } - } - if (ss != PJ_INVALID_SOCKET) { - rc = pj_sock_close(ss); - if (rc != PJ_SUCCESS) { - app_perror("...error in closing socket", rc); - return -1010; - } - } - - return retval; -} - -static int tcp_test(void) -{ - pj_sock_t cs, ss; - pj_status_t rc = 0, retval; - - PJ_LOG(3,("test", "...tcp_test()")); - - rc = app_socketpair(PJ_AF_INET, PJ_SOCK_STREAM, 0, &ss, &cs); - if (rc != PJ_SUCCESS) { - app_perror("...error: app_socketpair():", rc); - return -2000; - } - - /* Test send/recv with send() and recv() */ - retval = send_recv_test(PJ_SOCK_STREAM, ss, cs, NULL, NULL, 0); - - rc = pj_sock_close(cs); - if (rc != PJ_SUCCESS) { - app_perror("...error in closing socket", rc); - return -2000; - } - - rc = pj_sock_close(ss); - if (rc != PJ_SUCCESS) { - app_perror("...error in closing socket", rc); - return -2010; - } - - return retval; -} - -static int ioctl_test(void) -{ - return 0; -} - -int sock_test() -{ - int rc; - - pj_create_random_string(bigdata, BIG_DATA_LEN); - - rc = format_test(); - if (rc != 0) - return rc; - - rc = simple_sock_test(); - if (rc != 0) - return rc; - - rc = ioctl_test(); - if (rc != 0) - return rc; - - rc = udp_test(); - if (rc != 0) - return rc; - - rc = tcp_test(); - if (rc != 0) - return rc; - - return 0; -} - - -#else -/* To prevent warning about "translation unit is empty" - * when this test is disabled. - */ -int dummy_sock_test; -#endif /* INCLUDE_SOCK_TEST */ - +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/sock.c 4 10/29/05 11:51a Bennylp $ */ +/* $Log: /pjproject-0.3/pjlib/src/pjlib-test/sock.c $ + * + * 4 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 3 14/10/05 11:31 Bennylp + * Fixed bug when TCP data is received in chunks. + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 9/21/05 1:38p Bennylp + * Renamed from *.cpp + * + * 2 9/17/05 10:37a Bennylp + * Major reorganization towards version 0.3. + * + * 1 9/15/05 8:41p Bennylp + */ +#include +#include "test.h" + + +/** + * \page page_pjlib_sock_test Test: Socket + * + * This file provides implementation of \b sock_test(). It tests the + * various aspects of the socket API. + * + * \section sock_test_scope_sec Scope of the Test + * + * The scope of the test: + * - verify the validity of the address structs. + * - verify that address manipulation API works. + * - simple socket creation and destruction. + * - simple socket send/recv and sendto/recvfrom. + * - UDP connect() + * - send/recv big data. + * - all for both UDP and TCP. + * + * The APIs tested in this test: + * - pj_inet_aton() + * - pj_inet_ntoa() + * - pj_gethostname() + * - pj_sock_socket() + * - pj_sock_close() + * - pj_sock_send() + * - pj_sock_sendto() + * - pj_sock_recv() + * - pj_sock_recvfrom() + * - pj_sock_bind() + * - pj_sock_connect() + * - pj_sock_listen() + * - pj_sock_accept() + * + * + * This file is pjlib-test/sock.c + * + * \include pjlib-test/sock.c + */ + +#if INCLUDE_SOCK_TEST + +#define UDP_PORT 51234 +#define TCP_PORT (UDP_PORT+10) +#define BIG_DATA_LEN 9000 + +static char bigdata[BIG_DATA_LEN]; +static char bigbuffer[BIG_DATA_LEN]; + +static int format_test(void) +{ + pj_str_t s = pj_str("127.0.0.1"); + char *p; + pj_in_addr addr; + const pj_str_t *hostname; + + PJ_LOG(3,("test", "...format_test()")); + + /* pj_inet_aton() */ + if (pj_inet_aton(&s, &addr) != 1) + return -10; + + /* Check the result. */ + p = (char*)&addr; + if (p[0]!=127 || p[1]!=0 || p[2]!=0 || p[3]!=1) + return -15; + + /* pj_inet_ntoa() */ + p = pj_inet_ntoa(addr); + if (!p) + return -20; + + if (pj_strcmp2(&s, p) != 0) + return -30; + + /* pj_gethostname() */ + hostname = pj_gethostname(); + if (!hostname || !hostname->ptr || !hostname->slen) + return -40; + + /* pj_gethostaddr() */ + + return 0; +} + +static int simple_sock_test(void) +{ + int types[2]; + pj_sock_t sock; + int i; + pj_status_t rc = PJ_SUCCESS; + + types[0] = PJ_SOCK_STREAM; + types[1] = PJ_SOCK_DGRAM; + + PJ_LOG(3,("test", "...simple_sock_test()")); + + for (i=0; isin_addr)); + strcpy(addr_str, pj_inet_ntoa(addr.sin_addr)); + PJ_LOG(3,("test", "...error: src address mismatch (original=%s, " + "recvfrom addr=%s)", + srcaddr_str, addr_str)); + return -152; + } + + } else { + /* Repeat recv() until all data is received. + * This applies only for non-UDP of course, since for UDP + * we would expect all data to be received in one packet. + */ + total_received = 0; + do { + received = DATA_LEN-total_received; + rc = pj_sock_recv(ss, recvdata+total_received, &received, 0); + if (rc != PJ_SUCCESS) { + app_perror("...recv error", rc); + rc = -155; goto on_error; + } + if (received <= 0) { + PJ_LOG(3,("", "...error: socket has closed! (received=%d)", + received)); + rc = -156; goto on_error; + } + if (received != DATA_LEN-total_received) { + if (sock_type != PJ_SOCK_STREAM) { + PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes", + DATA_LEN-total_received, received)); + rc = -157; goto on_error; + } + } + total_received += received; + } while (total_received < DATA_LEN); + } + + TRACE_(("test", "....memcmp()")); + if (pj_memcmp(senddata, recvdata, DATA_LEN) != 0) { + PJ_LOG(3,("","...error: received data mismatch " + "(got:'%s' expecting:'%s'", + recvdata, senddata)); + rc = -160; goto on_error; + } + + /* + * Test send/recv big data. + */ + TRACE_(("test", "....sendto()")); + if (dstaddr) { + sent = BIG_DATA_LEN; + rc = pj_sock_sendto(cs, bigdata, &sent, 0, dstaddr, addrlen); + if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) { + app_perror("...sendto error", rc); + rc = -161; goto on_error; + } + } else { + sent = BIG_DATA_LEN; + rc = pj_sock_send(cs, bigdata, &sent, 0); + if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) { + app_perror("...send error", rc); + rc = -165; goto on_error; + } + } + + TRACE_(("test", "....recv()")); + + /* Repeat recv() until all data is received. + * This applies only for non-UDP of course, since for UDP + * we would expect all data to be received in one packet. + */ + total_received = 0; + do { + received = BIG_DATA_LEN-total_received; + rc = pj_sock_recv(ss, bigbuffer+total_received, &received, 0); + if (rc != PJ_SUCCESS) { + app_perror("...recv error", rc); + rc = -170; goto on_error; + } + if (received <= 0) { + PJ_LOG(3,("", "...error: socket has closed! (received=%d)", + received)); + rc = -173; goto on_error; + } + if (received != BIG_DATA_LEN-total_received) { + if (sock_type != PJ_SOCK_STREAM) { + PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes", + BIG_DATA_LEN-total_received, received)); + rc = -176; goto on_error; + } + } + total_received += received; + } while (total_received < BIG_DATA_LEN); + + TRACE_(("test", "....memcmp()")); + if (pj_memcmp(bigdata, bigbuffer, BIG_DATA_LEN) != 0) { + PJ_LOG(3,("", "...error: received data has been altered!")); + rc = -180; goto on_error; + } + + rc = 0; + +on_error: + return rc; +} + +static int udp_test(void) +{ + pj_sock_t cs = PJ_INVALID_SOCKET, ss = PJ_INVALID_SOCKET; + pj_sockaddr_in dstaddr, srcaddr; + pj_str_t s; + pj_status_t rc = 0, retval; + + PJ_LOG(3,("test", "...udp_test()")); + + rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ss); + if (rc != 0) { + app_perror("...error: unable to create socket", rc); + return -100; + } + + rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &cs); + if (rc != 0) + return -110; + + /* Bind server socket. */ + pj_memset(&dstaddr, 0, sizeof(dstaddr)); + dstaddr.sin_family = PJ_AF_INET; + dstaddr.sin_port = pj_htons(UDP_PORT); + dstaddr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1")); + + if ((rc=pj_sock_bind(ss, &dstaddr, sizeof(dstaddr))) != 0) { + app_perror("...bind error", rc); + rc = -120; goto on_error; + } + + /* Bind client socket. */ + pj_memset(&srcaddr, 0, sizeof(srcaddr)); + srcaddr.sin_family = PJ_AF_INET; + srcaddr.sin_port = pj_htons(UDP_PORT-1); + srcaddr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1")); + + if ((rc=pj_sock_bind(cs, &srcaddr, sizeof(srcaddr))) != 0) { + app_perror("...bind error", rc); + rc = -121; goto on_error; + } + + /* Test send/recv, with sendto */ + rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, &dstaddr, NULL, + sizeof(dstaddr)); + if (rc != 0) + goto on_error; + + /* Test send/recv, with sendto and recvfrom */ + rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, &dstaddr, + &srcaddr, sizeof(dstaddr)); + if (rc != 0) + goto on_error; + + /* connect() the sockets. */ + rc = pj_sock_connect(cs, &dstaddr, sizeof(dstaddr)); + if (rc != 0) { + app_perror("...connect() error", rc); + rc = -122; goto on_error; + } + + /* Test send/recv with send() */ + rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, NULL, NULL, 0); + if (rc != 0) + goto on_error; + + /* Test send/recv with send() and recvfrom */ + rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, NULL, &srcaddr, + sizeof(srcaddr)); + if (rc != 0) + goto on_error; + +on_error: + retval = rc; + if (cs != PJ_INVALID_SOCKET) { + rc = pj_sock_close(cs); + if (rc != PJ_SUCCESS) { + app_perror("...error in closing socket", rc); + return -1000; + } + } + if (ss != PJ_INVALID_SOCKET) { + rc = pj_sock_close(ss); + if (rc != PJ_SUCCESS) { + app_perror("...error in closing socket", rc); + return -1010; + } + } + + return retval; +} + +static int tcp_test(void) +{ + pj_sock_t cs, ss; + pj_status_t rc = 0, retval; + + PJ_LOG(3,("test", "...tcp_test()")); + + rc = app_socketpair(PJ_AF_INET, PJ_SOCK_STREAM, 0, &ss, &cs); + if (rc != PJ_SUCCESS) { + app_perror("...error: app_socketpair():", rc); + return -2000; + } + + /* Test send/recv with send() and recv() */ + retval = send_recv_test(PJ_SOCK_STREAM, ss, cs, NULL, NULL, 0); + + rc = pj_sock_close(cs); + if (rc != PJ_SUCCESS) { + app_perror("...error in closing socket", rc); + return -2000; + } + + rc = pj_sock_close(ss); + if (rc != PJ_SUCCESS) { + app_perror("...error in closing socket", rc); + return -2010; + } + + return retval; +} + +static int ioctl_test(void) +{ + return 0; +} + +int sock_test() +{ + int rc; + + pj_create_random_string(bigdata, BIG_DATA_LEN); + + rc = format_test(); + if (rc != 0) + return rc; + + rc = simple_sock_test(); + if (rc != 0) + return rc; + + rc = ioctl_test(); + if (rc != 0) + return rc; + + rc = udp_test(); + if (rc != 0) + return rc; + + rc = tcp_test(); + if (rc != 0) + return rc; + + return 0; +} + + +#else +/* To prevent warning about "translation unit is empty" + * when this test is disabled. + */ +int dummy_sock_test; +#endif /* INCLUDE_SOCK_TEST */ + diff --git a/pjlib/src/pjlib-test/sock_perf.c b/pjlib/src/pjlib-test/sock_perf.c index 9e800432..c20016d6 100644 --- a/pjlib/src/pjlib-test/sock_perf.c +++ b/pjlib/src/pjlib-test/sock_perf.c @@ -1,183 +1,183 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/sock_perf.c 4 10/29/05 11:51a Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pjlib-test/sock_perf.c $ - * - * 4 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 3 14/10/05 11:31 Bennylp - * Fixed bug when TCP data is part_received in chunks. - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 10/11/05 11:18p Bennylp - * Created. - * - */ -#include "test.h" -#include -#include - - -/** - * \page page_pjlib_sock_perf_test Test: Socket Performance - * - * Test the performance of the socket communication. This will perform - * simple producer-consumer type of test, where we calculate how long - * does it take to send certain number of packets from producer to - * consumer. - * - * This file is pjlib-test/sock_perf.c - * - * \include pjlib-test/sock_perf.c - */ - -#if INCLUDE_SOCK_PERF_TEST - -/* - * sock_producer_consumer() - * - * Simple producer-consumer benchmarking. Send loop number of - * buf_size size packets as fast as possible. - */ -static int sock_producer_consumer(int sock_type, - unsigned buf_size, - unsigned loop, - unsigned *p_bandwidth) -{ - pj_sock_t consumer, producer; - pj_pool_t *pool; - char *outgoing_buffer, *incoming_buffer; - pj_timestamp start, stop; - unsigned i; - pj_highprec_t elapsed, bandwidth; - pj_size_t total_received; - pj_status_t rc; - - /* Create pool. */ - pool = pj_pool_create(mem, NULL, 4096, 4096, NULL); - if (!pool) - return -10; - - /* Create producer-consumer pair. */ - rc = app_socketpair(PJ_AF_INET, sock_type, 0, &consumer, &producer); - if (rc != PJ_SUCCESS) { - app_perror("...error: create socket pair", rc); - return -20; - } - - /* Create buffers. */ - outgoing_buffer = pj_pool_alloc(pool, buf_size); - incoming_buffer = pj_pool_alloc(pool, buf_size); - - /* Start loop. */ - pj_get_timestamp(&start); - total_received = 0; - for (i=0; i 10) - break; - } - - /* Stop timer. */ - pj_get_timestamp(&stop); - - elapsed = pj_elapsed_usec(&start, &stop); - - /* bandwidth = total_received * 1000 / elapsed */ - bandwidth = total_received; - pj_highprec_mul(bandwidth, 1000); - pj_highprec_div(bandwidth, elapsed); - - *p_bandwidth = (pj_uint32_t)bandwidth; - - /* Close sockets. */ - pj_sock_close(consumer); - pj_sock_close(producer); - - /* Done */ - pj_pool_release(pool); - - return 0; -} - -/* - * sock_perf_test() - * - * Main test entry. - */ -int sock_perf_test(void) -{ - enum { LOOP = 64 * 1024 }; - int rc; - unsigned bandwidth; - - PJ_LOG(3,("", "...benchmarking socket " - "(2 sockets, packet=512, single threaded):")); - - /* Benchmarking UDP */ - rc = sock_producer_consumer(PJ_SOCK_DGRAM, 512, LOOP, &bandwidth); - if (rc != 0) return rc; - PJ_LOG(3,("", "....bandwidth UDP = %d KB/s", bandwidth)); - - /* Benchmarking TCP */ - rc = sock_producer_consumer(PJ_SOCK_STREAM, 512, LOOP, &bandwidth); - if (rc != 0) return rc; - PJ_LOG(3,("", "....bandwidth TCP = %d KB/s", bandwidth)); - - return rc; -} - - -#else -/* To prevent warning about "translation unit is empty" - * when this test is disabled. - */ -int dummy_sock_perf_test; -#endif /* INCLUDE_SOCK_PERF_TEST */ - - +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/sock_perf.c 4 10/29/05 11:51a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pjlib-test/sock_perf.c $ + * + * 4 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 3 14/10/05 11:31 Bennylp + * Fixed bug when TCP data is part_received in chunks. + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 10/11/05 11:18p Bennylp + * Created. + * + */ +#include "test.h" +#include +#include + + +/** + * \page page_pjlib_sock_perf_test Test: Socket Performance + * + * Test the performance of the socket communication. This will perform + * simple producer-consumer type of test, where we calculate how long + * does it take to send certain number of packets from producer to + * consumer. + * + * This file is pjlib-test/sock_perf.c + * + * \include pjlib-test/sock_perf.c + */ + +#if INCLUDE_SOCK_PERF_TEST + +/* + * sock_producer_consumer() + * + * Simple producer-consumer benchmarking. Send loop number of + * buf_size size packets as fast as possible. + */ +static int sock_producer_consumer(int sock_type, + unsigned buf_size, + unsigned loop, + unsigned *p_bandwidth) +{ + pj_sock_t consumer, producer; + pj_pool_t *pool; + char *outgoing_buffer, *incoming_buffer; + pj_timestamp start, stop; + unsigned i; + pj_highprec_t elapsed, bandwidth; + pj_size_t total_received; + pj_status_t rc; + + /* Create pool. */ + pool = pj_pool_create(mem, NULL, 4096, 4096, NULL); + if (!pool) + return -10; + + /* Create producer-consumer pair. */ + rc = app_socketpair(PJ_AF_INET, sock_type, 0, &consumer, &producer); + if (rc != PJ_SUCCESS) { + app_perror("...error: create socket pair", rc); + return -20; + } + + /* Create buffers. */ + outgoing_buffer = pj_pool_alloc(pool, buf_size); + incoming_buffer = pj_pool_alloc(pool, buf_size); + + /* Start loop. */ + pj_get_timestamp(&start); + total_received = 0; + for (i=0; i 10) + break; + } + + /* Stop timer. */ + pj_get_timestamp(&stop); + + elapsed = pj_elapsed_usec(&start, &stop); + + /* bandwidth = total_received * 1000 / elapsed */ + bandwidth = total_received; + pj_highprec_mul(bandwidth, 1000); + pj_highprec_div(bandwidth, elapsed); + + *p_bandwidth = (pj_uint32_t)bandwidth; + + /* Close sockets. */ + pj_sock_close(consumer); + pj_sock_close(producer); + + /* Done */ + pj_pool_release(pool); + + return 0; +} + +/* + * sock_perf_test() + * + * Main test entry. + */ +int sock_perf_test(void) +{ + enum { LOOP = 64 * 1024 }; + int rc; + unsigned bandwidth; + + PJ_LOG(3,("", "...benchmarking socket " + "(2 sockets, packet=512, single threaded):")); + + /* Benchmarking UDP */ + rc = sock_producer_consumer(PJ_SOCK_DGRAM, 512, LOOP, &bandwidth); + if (rc != 0) return rc; + PJ_LOG(3,("", "....bandwidth UDP = %d KB/s", bandwidth)); + + /* Benchmarking TCP */ + rc = sock_producer_consumer(PJ_SOCK_STREAM, 512, LOOP, &bandwidth); + if (rc != 0) return rc; + PJ_LOG(3,("", "....bandwidth TCP = %d KB/s", bandwidth)); + + return rc; +} + + +#else +/* To prevent warning about "translation unit is empty" + * when this test is disabled. + */ +int dummy_sock_perf_test; +#endif /* INCLUDE_SOCK_PERF_TEST */ + + diff --git a/pjlib/src/pjlib-test/string.c b/pjlib/src/pjlib-test/string.c index 1a3de325..3714ecaa 100644 --- a/pjlib/src/pjlib-test/string.c +++ b/pjlib/src/pjlib-test/string.c @@ -1,168 +1,168 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/string.c 2 10/14/05 12:26a Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pjlib-test/string.c $ - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 10/05/05 5:13p Bennylp - * Created. - * - */ -#include -#include -#include -#include "test.h" - -/** - * \page page_pjlib_string_test Test: String - * - * This file provides implementation of \b string_test(). It tests the - * functionality of the string API. - * - * \section sleep_test_sec Scope of the Test - * - * API tested: - * - pj_str() - * - pj_strcmp() - * - pj_strcmp2() - * - pj_stricmp() - * - pj_strlen() - * - pj_strncmp() - * - pj_strnicmp() - * - pj_strchr() - * - pj_strdup() - * - pj_strdup2() - * - pj_strcpy() - * - pj_strcat() - * - pj_strtrim() - * - pj_utoa() - * - pj_strtoul() - * - pj_create_random_string() - * - * - * This file is pjlib-test/string.c - * - * \include pjlib-test/string.c - */ - -#if INCLUDE_STRING_TEST - -#ifdef _MSC_VER -# pragma warning(disable: 4204) -#endif - -#define HELLO_WORLD "Hello World" -#define JUST_HELLO "Hello" -#define UL_VALUE 3456789012UL - -int string_test(void) -{ - const pj_str_t hello_world = { HELLO_WORLD, strlen(HELLO_WORLD) }; - const pj_str_t just_hello = { JUST_HELLO, strlen(JUST_HELLO) }; - pj_str_t s1, s2, s3, s4, s5; - enum { RCOUNT = 10, RLEN = 16 }; - pj_str_t random[RCOUNT]; - pj_pool_t *pool; - int i; - - pool = pj_pool_create(mem, NULL, 4096, 0, NULL); - if (!pool) return -5; - - /* - * pj_str(), pj_strcmp(), pj_stricmp(), pj_strlen(), - * pj_strncmp(), pj_strchr() - */ - s1 = pj_str(HELLO_WORLD); - if (pj_strcmp(&s1, &hello_world) != 0) - return -10; - if (pj_stricmp(&s1, &hello_world) != 0) - return -20; - if (pj_strcmp(&s1, &just_hello) <= 0) - return -30; - if (pj_stricmp(&s1, &just_hello) <= 0) - return -40; - if (pj_strlen(&s1) != strlen(HELLO_WORLD)) - return -50; - if (pj_strncmp(&s1, &hello_world, 5) != 0) - return -60; - if (pj_strnicmp(&s1, &hello_world, 5) != 0) - return -70; - if (pj_strchr(&s1, HELLO_WORLD[1]) != s1.ptr+1) - return -80; - - /* - * pj_strdup() - */ - if (!pj_strdup(pool, &s2, &s1)) - return -100; - if (pj_strcmp(&s1, &s2) != 0) - return -110; - - /* - * pj_strcpy(), pj_strcat() - */ - s3.ptr = pj_pool_alloc(pool, 256); - if (!s3.ptr) - return -200; - pj_strcpy(&s3, &s2); - pj_strcat(&s3, &just_hello); - - if (pj_strcmp2(&s3, HELLO_WORLD JUST_HELLO) != 0) - return -210; - - /* - * pj_strdup2(), pj_strtrim(). - */ - pj_strdup2(pool, &s4, " " HELLO_WORLD "\t "); - pj_strtrim(&s4); - if (pj_strcmp2(&s4, HELLO_WORLD) != 0) - return -250; - - /* - * pj_utoa() - */ - s5.ptr = pj_pool_alloc(pool, 16); - if (!s5.ptr) - return -270; - s5.slen = pj_utoa(UL_VALUE, s5.ptr); - - /* - * pj_strtoul() - */ - if (pj_strtoul(&s5) != UL_VALUE) - return -280; - - /* - * pj_create_random_string() - * Check that no duplicate strings are returned. - */ - for (i=0; i +#include +#include +#include "test.h" + +/** + * \page page_pjlib_string_test Test: String + * + * This file provides implementation of \b string_test(). It tests the + * functionality of the string API. + * + * \section sleep_test_sec Scope of the Test + * + * API tested: + * - pj_str() + * - pj_strcmp() + * - pj_strcmp2() + * - pj_stricmp() + * - pj_strlen() + * - pj_strncmp() + * - pj_strnicmp() + * - pj_strchr() + * - pj_strdup() + * - pj_strdup2() + * - pj_strcpy() + * - pj_strcat() + * - pj_strtrim() + * - pj_utoa() + * - pj_strtoul() + * - pj_create_random_string() + * + * + * This file is pjlib-test/string.c + * + * \include pjlib-test/string.c + */ + +#if INCLUDE_STRING_TEST + +#ifdef _MSC_VER +# pragma warning(disable: 4204) +#endif + +#define HELLO_WORLD "Hello World" +#define JUST_HELLO "Hello" +#define UL_VALUE 3456789012UL + +int string_test(void) +{ + const pj_str_t hello_world = { HELLO_WORLD, strlen(HELLO_WORLD) }; + const pj_str_t just_hello = { JUST_HELLO, strlen(JUST_HELLO) }; + pj_str_t s1, s2, s3, s4, s5; + enum { RCOUNT = 10, RLEN = 16 }; + pj_str_t random[RCOUNT]; + pj_pool_t *pool; + int i; + + pool = pj_pool_create(mem, NULL, 4096, 0, NULL); + if (!pool) return -5; + + /* + * pj_str(), pj_strcmp(), pj_stricmp(), pj_strlen(), + * pj_strncmp(), pj_strchr() + */ + s1 = pj_str(HELLO_WORLD); + if (pj_strcmp(&s1, &hello_world) != 0) + return -10; + if (pj_stricmp(&s1, &hello_world) != 0) + return -20; + if (pj_strcmp(&s1, &just_hello) <= 0) + return -30; + if (pj_stricmp(&s1, &just_hello) <= 0) + return -40; + if (pj_strlen(&s1) != strlen(HELLO_WORLD)) + return -50; + if (pj_strncmp(&s1, &hello_world, 5) != 0) + return -60; + if (pj_strnicmp(&s1, &hello_world, 5) != 0) + return -70; + if (pj_strchr(&s1, HELLO_WORLD[1]) != s1.ptr+1) + return -80; + + /* + * pj_strdup() + */ + if (!pj_strdup(pool, &s2, &s1)) + return -100; + if (pj_strcmp(&s1, &s2) != 0) + return -110; + + /* + * pj_strcpy(), pj_strcat() + */ + s3.ptr = pj_pool_alloc(pool, 256); + if (!s3.ptr) + return -200; + pj_strcpy(&s3, &s2); + pj_strcat(&s3, &just_hello); + + if (pj_strcmp2(&s3, HELLO_WORLD JUST_HELLO) != 0) + return -210; + + /* + * pj_strdup2(), pj_strtrim(). + */ + pj_strdup2(pool, &s4, " " HELLO_WORLD "\t "); + pj_strtrim(&s4); + if (pj_strcmp2(&s4, HELLO_WORLD) != 0) + return -250; + + /* + * pj_utoa() + */ + s5.ptr = pj_pool_alloc(pool, 16); + if (!s5.ptr) + return -270; + s5.slen = pj_utoa(UL_VALUE, s5.ptr); + + /* + * pj_strtoul() + */ + if (pj_strtoul(&s5) != UL_VALUE) + return -280; + + /* + * pj_create_random_string() + * Check that no duplicate strings are returned. + */ + for (i=0; i -#ifdef _MSC_VER -# pragma warning(disable:4127) -#endif - -#define DO_TEST(test) do { \ - PJ_LOG(3, ("test", "Running %s...", #test)); \ - rc = test; \ - PJ_LOG(3, ("test", \ - "%s(%d)", \ - (rc ? "..ERROR" : "..success"), rc)); \ - if (rc!=0) goto on_return; \ - } while (0) - - -pj_pool_factory *mem; - -int param_echo_sock_type; -const char *param_echo_server = ECHO_SERVER_ADDRESS; -int param_echo_port = ECHO_SERVER_START_PORT; - -int test_inner(void) -{ - pj_caching_pool caching_pool; - const char *filename; - int line; - int rc = 0; - - mem = &caching_pool.factory; - - rc = pj_init(); - if (rc != 0) { - app_perror("pj_init() error!!", rc); - return rc; - } - - pj_log_set_level(3); - pj_log_set_decor(PJ_LOG_HAS_NEWLINE); - pj_dump_config(); - pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 ); - -#if INCLUDE_ERRNO_TEST - DO_TEST( errno_test() ); -#endif - -#if INCLUDE_TIMESTAMP_TEST - DO_TEST( timestamp_test() ); -#endif - -#if INCLUDE_EXCEPTION_TEST - DO_TEST( exception_test() ); -#endif - -#if INCLUDE_RAND_TEST - DO_TEST( rand_test() ); -#endif - -#if INCLUDE_LIST_TEST - DO_TEST( list_test() ); -#endif - -#if INCLUDE_POOL_TEST - DO_TEST( pool_test() ); -#endif - -#if INCLUDE_POOL_PERF_TEST - DO_TEST( pool_perf_test() ); -#endif - -#if INCLUDE_STRING_TEST - DO_TEST( string_test() ); -#endif - -#if INCLUDE_FIFOBUF_TEST - DO_TEST( fifobuf_test() ); -#endif - -#if INCLUDE_RBTREE_TEST - DO_TEST( rbtree_test() ); -#endif - -#if INCLUDE_ATOMIC_TEST - DO_TEST( atomic_test() ); -#endif - -#if INCLUDE_MUTEX_TEST - DO_TEST( mutex_test() ); -#endif - -#if INCLUDE_TIMER_TEST - DO_TEST( timer_test() ); -#endif - -#if INCLUDE_SLEEP_TEST - DO_TEST( sleep_test() ); -#endif - -#if INCLUDE_THREAD_TEST - DO_TEST( thread_test() ); -#endif - -#if INCLUDE_SOCK_TEST - DO_TEST( sock_test() ); -#endif - -#if INCLUDE_SOCK_PERF_TEST - DO_TEST( sock_perf_test() ); -#endif - -#if INCLUDE_SELECT_TEST - DO_TEST( select_test() ); -#endif - -#if INCLUDE_UDP_IOQUEUE_TEST - DO_TEST( udp_ioqueue_test() ); -#endif - -#if PJ_HAS_TCP && INCLUDE_TCP_IOQUEUE_TEST - DO_TEST( tcp_ioqueue_test() ); -#endif - -#if INCLUDE_IOQUEUE_PERF_TEST - DO_TEST( ioqueue_perf_test() ); -#endif - -#if INCLUDE_XML_TEST - DO_TEST( xml_test() ); -#endif - -#if INCLUDE_ECHO_SERVER - //echo_server(); - echo_srv_sync(); -#elif INCLUDE_ECHO_CLIENT - if (param_echo_sock_type == 0) - param_echo_sock_type = PJ_SOCK_DGRAM; - - echo_client( param_echo_sock_type, - param_echo_server, - param_echo_port); -#endif - - goto on_return; - -on_return: - - pj_caching_pool_destroy( &caching_pool ); - - PJ_LOG(3,("test", "")); - - pj_thread_get_stack_info(pj_thread_this(), &filename, &line); - PJ_LOG(3,("test", "Stack max usage: %u, deepest: %s:%u", - pj_thread_get_stack_max_usage(pj_thread_this()), - filename, line)); - if (rc == 0) - PJ_LOG(3,("test", "Looks like everything is okay!..")); - else - PJ_LOG(3,("test", "Test completed with error(s)")); - return 0; -} - -int test_main(void) -{ - PJ_USE_EXCEPTION; - - PJ_TRY { - return test_inner(); - } - PJ_DEFAULT { - int id = PJ_GET_EXCEPTION(); - PJ_LOG(3,("test", "FATAL: unhandled exception id %d (%s)", - id, pj_exception_id_name(id))); - } - PJ_END; - - return -1; -} +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/test.c 4 29/10/05 21:33 Bennylp $ + */ +/* + * $Log: /pjproject-0.3/pjlib/src/pjlib-test/test.c $ + * + * 4 29/10/05 21:33 Bennylp + * Changed echo_server() to echo_srv_sync() + * + * 3 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 10/05/05 5:13p Bennylp + * Created. + * + */ +#include "test.h" +#include +#ifdef _MSC_VER +# pragma warning(disable:4127) +#endif + +#define DO_TEST(test) do { \ + PJ_LOG(3, ("test", "Running %s...", #test)); \ + rc = test; \ + PJ_LOG(3, ("test", \ + "%s(%d)", \ + (rc ? "..ERROR" : "..success"), rc)); \ + if (rc!=0) goto on_return; \ + } while (0) + + +pj_pool_factory *mem; + +int param_echo_sock_type; +const char *param_echo_server = ECHO_SERVER_ADDRESS; +int param_echo_port = ECHO_SERVER_START_PORT; + +int test_inner(void) +{ + pj_caching_pool caching_pool; + const char *filename; + int line; + int rc = 0; + + mem = &caching_pool.factory; + + rc = pj_init(); + if (rc != 0) { + app_perror("pj_init() error!!", rc); + return rc; + } + + pj_log_set_level(3); + pj_log_set_decor(PJ_LOG_HAS_NEWLINE); + pj_dump_config(); + pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 ); + +#if INCLUDE_ERRNO_TEST + DO_TEST( errno_test() ); +#endif + +#if INCLUDE_TIMESTAMP_TEST + DO_TEST( timestamp_test() ); +#endif + +#if INCLUDE_EXCEPTION_TEST + DO_TEST( exception_test() ); +#endif + +#if INCLUDE_RAND_TEST + DO_TEST( rand_test() ); +#endif + +#if INCLUDE_LIST_TEST + DO_TEST( list_test() ); +#endif + +#if INCLUDE_POOL_TEST + DO_TEST( pool_test() ); +#endif + +#if INCLUDE_POOL_PERF_TEST + DO_TEST( pool_perf_test() ); +#endif + +#if INCLUDE_STRING_TEST + DO_TEST( string_test() ); +#endif + +#if INCLUDE_FIFOBUF_TEST + DO_TEST( fifobuf_test() ); +#endif + +#if INCLUDE_RBTREE_TEST + DO_TEST( rbtree_test() ); +#endif + +#if INCLUDE_ATOMIC_TEST + DO_TEST( atomic_test() ); +#endif + +#if INCLUDE_MUTEX_TEST + DO_TEST( mutex_test() ); +#endif + +#if INCLUDE_TIMER_TEST + DO_TEST( timer_test() ); +#endif + +#if INCLUDE_SLEEP_TEST + DO_TEST( sleep_test() ); +#endif + +#if INCLUDE_THREAD_TEST + DO_TEST( thread_test() ); +#endif + +#if INCLUDE_SOCK_TEST + DO_TEST( sock_test() ); +#endif + +#if INCLUDE_SOCK_PERF_TEST + DO_TEST( sock_perf_test() ); +#endif + +#if INCLUDE_SELECT_TEST + DO_TEST( select_test() ); +#endif + +#if INCLUDE_UDP_IOQUEUE_TEST + DO_TEST( udp_ioqueue_test() ); +#endif + +#if PJ_HAS_TCP && INCLUDE_TCP_IOQUEUE_TEST + DO_TEST( tcp_ioqueue_test() ); +#endif + +#if INCLUDE_IOQUEUE_PERF_TEST + DO_TEST( ioqueue_perf_test() ); +#endif + +#if INCLUDE_XML_TEST + DO_TEST( xml_test() ); +#endif + +#if INCLUDE_ECHO_SERVER + //echo_server(); + echo_srv_sync(); +#elif INCLUDE_ECHO_CLIENT + if (param_echo_sock_type == 0) + param_echo_sock_type = PJ_SOCK_DGRAM; + + echo_client( param_echo_sock_type, + param_echo_server, + param_echo_port); +#endif + + goto on_return; + +on_return: + + pj_caching_pool_destroy( &caching_pool ); + + PJ_LOG(3,("test", "")); + + pj_thread_get_stack_info(pj_thread_this(), &filename, &line); + PJ_LOG(3,("test", "Stack max usage: %u, deepest: %s:%u", + pj_thread_get_stack_max_usage(pj_thread_this()), + filename, line)); + if (rc == 0) + PJ_LOG(3,("test", "Looks like everything is okay!..")); + else + PJ_LOG(3,("test", "Test completed with error(s)")); + return 0; +} + +int test_main(void) +{ + PJ_USE_EXCEPTION; + + PJ_TRY { + return test_inner(); + } + PJ_DEFAULT { + int id = PJ_GET_EXCEPTION(); + PJ_LOG(3,("test", "FATAL: unhandled exception id %d (%s)", + id, pj_exception_id_name(id))); + } + PJ_END; + + return -1; +} diff --git a/pjlib/src/pjlib-test/test.h b/pjlib/src/pjlib-test/test.h index 475cdff6..f02cdd1d 100644 --- a/pjlib/src/pjlib-test/test.h +++ b/pjlib/src/pjlib-test/test.h @@ -1,90 +1,90 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/test.h 4 10/29/05 10:28p Bennylp $ */ -#ifndef __PJLIB_TEST_H__ -#define __PJLIB_TEST_H__ - -#include - -#define GROUP_LIBC 1 -#define GROUP_OS 1 -#define GROUP_DATA_STRUCTURE 1 -#define GROUP_NETWORK 1 -#define GROUP_EXTRA 1 - -#define INCLUDE_ERRNO_TEST GROUP_LIBC -#define INCLUDE_TIMESTAMP_TEST GROUP_OS -#define INCLUDE_EXCEPTION_TEST GROUP_LIBC -#define INCLUDE_RAND_TEST GROUP_LIBC -#define INCLUDE_LIST_TEST GROUP_DATA_STRUCTURE -#define INCLUDE_POOL_TEST GROUP_LIBC -#define INCLUDE_POOL_PERF_TEST (PJ_HAS_MALLOC && GROUP_LIBC) -#define INCLUDE_STRING_TEST GROUP_DATA_STRUCTURE -#define INCLUDE_FIFOBUF_TEST GROUP_DATA_STRUCTURE -#define INCLUDE_RBTREE_TEST GROUP_DATA_STRUCTURE -#define INCLUDE_TIMER_TEST GROUP_DATA_STRUCTURE -#define INCLUDE_ATOMIC_TEST GROUP_OS -#define INCLUDE_MUTEX_TEST GROUP_OS -#define INCLUDE_SLEEP_TEST GROUP_OS -#define INCLUDE_THREAD_TEST GROUP_OS -#define INCLUDE_SOCK_TEST GROUP_NETWORK -#define INCLUDE_SOCK_PERF_TEST GROUP_NETWORK -#define INCLUDE_SELECT_TEST GROUP_NETWORK -#define INCLUDE_UDP_IOQUEUE_TEST GROUP_NETWORK -#define INCLUDE_TCP_IOQUEUE_TEST GROUP_NETWORK -#define INCLUDE_IOQUEUE_PERF_TEST GROUP_NETWORK -#define INCLUDE_XML_TEST GROUP_EXTRA - - -#define INCLUDE_ECHO_SERVER 0 -#define INCLUDE_ECHO_CLIENT 0 - -#define ECHO_SERVER_MAX_THREADS 4 -#define ECHO_SERVER_START_PORT 65000 -#define ECHO_SERVER_ADDRESS "compaq.home" -#define ECHO_SERVER_DURATION_MSEC (60*60*1000) - -#define ECHO_CLIENT_MAX_THREADS 10 - -PJ_BEGIN_DECL - -extern int errno_test(void); -extern int timestamp_test(void); -extern int exception_test(void); -extern int rand_test(void); -extern int list_test(void); -extern int pool_test(void); -extern int pool_perf_test(void); -extern int string_test(void); -extern int fifobuf_test(void); -extern int timer_test(void); -extern int rbtree_test(void); -extern int atomic_test(void); -extern int mutex_test(void); -extern int sleep_test(void); -extern int thread_test(void); -extern int sock_test(void); -extern int sock_perf_test(void); -extern int select_test(void); -extern int udp_ioqueue_test(void); -extern int tcp_ioqueue_test(void); -extern int ioqueue_perf_test(void); -extern int xml_test(void); - -extern int echo_server(void); -extern int echo_client(int sock_type, const char *server, int port); - -extern pj_pool_factory *mem; - -extern int test_main(void); -extern void app_perror(const char *msg, pj_status_t err); -extern pj_status_t app_socket(int family, int type, int proto, int port, - pj_sock_t *ptr_sock); -extern pj_status_t app_socketpair(int family, int type, int protocol, - pj_sock_t *server, pj_sock_t *client); - -//#define TRACE_(expr) PJ_LOG(3,expr) -#define TRACE_(expr) - -PJ_END_DECL - -#endif /* __PJLIB_TEST_H__ */ - +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/test.h 4 10/29/05 10:28p Bennylp $ */ +#ifndef __PJLIB_TEST_H__ +#define __PJLIB_TEST_H__ + +#include + +#define GROUP_LIBC 0 +#define GROUP_OS 0 +#define GROUP_DATA_STRUCTURE 0 +#define GROUP_NETWORK 0 +#define GROUP_EXTRA 0 + +#define INCLUDE_ERRNO_TEST GROUP_LIBC +#define INCLUDE_TIMESTAMP_TEST GROUP_OS +#define INCLUDE_EXCEPTION_TEST GROUP_LIBC +#define INCLUDE_RAND_TEST GROUP_LIBC +#define INCLUDE_LIST_TEST GROUP_DATA_STRUCTURE +#define INCLUDE_POOL_TEST GROUP_LIBC +#define INCLUDE_POOL_PERF_TEST (PJ_HAS_MALLOC && GROUP_LIBC) +#define INCLUDE_STRING_TEST GROUP_DATA_STRUCTURE +#define INCLUDE_FIFOBUF_TEST 0 // GROUP_DATA_STRUCTURE +#define INCLUDE_RBTREE_TEST GROUP_DATA_STRUCTURE +#define INCLUDE_TIMER_TEST GROUP_DATA_STRUCTURE +#define INCLUDE_ATOMIC_TEST GROUP_OS +#define INCLUDE_MUTEX_TEST GROUP_OS +#define INCLUDE_SLEEP_TEST GROUP_OS +#define INCLUDE_THREAD_TEST GROUP_OS +#define INCLUDE_SOCK_TEST GROUP_NETWORK +#define INCLUDE_SOCK_PERF_TEST GROUP_NETWORK +#define INCLUDE_SELECT_TEST GROUP_NETWORK +#define INCLUDE_UDP_IOQUEUE_TEST GROUP_NETWORK +#define INCLUDE_TCP_IOQUEUE_TEST GROUP_NETWORK +#define INCLUDE_IOQUEUE_PERF_TEST GROUP_NETWORK +#define INCLUDE_XML_TEST GROUP_EXTRA + + +#define INCLUDE_ECHO_SERVER 0 +#define INCLUDE_ECHO_CLIENT 1 + +#define ECHO_SERVER_MAX_THREADS 4 +#define ECHO_SERVER_START_PORT 65000 +#define ECHO_SERVER_ADDRESS "compaq.home" +#define ECHO_SERVER_DURATION_MSEC (60*60*1000) + +#define ECHO_CLIENT_MAX_THREADS 2 + +PJ_BEGIN_DECL + +extern int errno_test(void); +extern int timestamp_test(void); +extern int exception_test(void); +extern int rand_test(void); +extern int list_test(void); +extern int pool_test(void); +extern int pool_perf_test(void); +extern int string_test(void); +extern int fifobuf_test(void); +extern int timer_test(void); +extern int rbtree_test(void); +extern int atomic_test(void); +extern int mutex_test(void); +extern int sleep_test(void); +extern int thread_test(void); +extern int sock_test(void); +extern int sock_perf_test(void); +extern int select_test(void); +extern int udp_ioqueue_test(void); +extern int tcp_ioqueue_test(void); +extern int ioqueue_perf_test(void); +extern int xml_test(void); + +extern int echo_server(void); +extern int echo_client(int sock_type, const char *server, int port); + +extern pj_pool_factory *mem; + +extern int test_main(void); +extern void app_perror(const char *msg, pj_status_t err); +extern pj_status_t app_socket(int family, int type, int proto, int port, + pj_sock_t *ptr_sock); +extern pj_status_t app_socketpair(int family, int type, int protocol, + pj_sock_t *server, pj_sock_t *client); + +//#define TRACE_(expr) PJ_LOG(3,expr) +#define TRACE_(expr) + +PJ_END_DECL + +#endif /* __PJLIB_TEST_H__ */ + diff --git a/pjlib/src/pjlib-test/thread.c b/pjlib/src/pjlib-test/thread.c index f41ec16e..a9925383 100644 --- a/pjlib/src/pjlib-test/thread.c +++ b/pjlib/src/pjlib-test/thread.c @@ -1,290 +1,290 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/thread.c 4 10/29/05 11:51a Bennylp $ - */ -/* - * $Log: /pjproject-0.3/pjlib/src/pjlib-test/thread.c $ - * - * 4 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 3 14/10/05 11:32 Bennylp - * More lenient with timeslice difference. - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 10/11/05 12:39a Bennylp - * Created. - * - */ -#include "test.h" - -/** - * \page page_pjlib_thread_test Test: Thread Test - * - * This file contains \a thread_test() definition. - * - * \section thread_test_scope_sec Scope of Test - * This tests: - * - whether PJ_THREAD_SUSPENDED flag works. - * - whether multithreading works. - * - whether thread timeslicing works, and threads have equal - * time-slice proportion. - * - * APIs tested: - * - pj_thread_create() - * - pj_thread_register() - * - pj_thread_this() - * - pj_thread_get_name() - * - pj_thread_destroy() - * - pj_thread_resume() - * - pj_thread_sleep() - * - pj_thread_join() - * - pj_thread_destroy() - * - * - * This file is pjlib-test/thread.c - * - * \include pjlib-test/thread.c - */ -#if INCLUDE_THREAD_TEST - -#include - -#define THIS_FILE "thread_test" - -static int quit_flag=0; - -/* - * The thread's entry point. - * - * Each of the thread mainly will just execute the loop which - * increments a variable. - */ -static void* thread_proc(pj_uint32_t *pcounter) -{ - /* Test that pj_thread_register() works. */ - pj_thread_desc desc; - pj_thread_t *this_thread; - pj_status_t rc; - - rc = pj_thread_register("thread", desc, &this_thread); - if (rc != PJ_SUCCESS) { - app_perror("...error in pj_thread_register", rc); - return NULL; - } - - /* Test that pj_thread_this() works */ - this_thread = pj_thread_this(); - if (this_thread == NULL) { - PJ_LOG(3,(THIS_FILE, "...error: pj_thread_this() returns NULL!")); - return NULL; - } - - /* Test that pj_thread_get_name() works */ - if (pj_thread_get_name(this_thread) == NULL) { - PJ_LOG(3,(THIS_FILE, "...error: pj_thread_get_name() returns NULL!")); - return NULL; - } - - /* Main loop */ - for (;!quit_flag;) { - (*pcounter)++; - //Must sleep if platform doesn't do time-slicing. - pj_thread_sleep(0); - } - - return NULL; -} - -/* - * simple_thread() - */ -static int simple_thread(const char *title, unsigned flags) -{ - pj_pool_t *pool; - pj_thread_t *thread; - pj_status_t rc; - pj_uint32_t counter = 0; - - PJ_LOG(3,(THIS_FILE, "..%s", title)); - - pool = pj_pool_create(mem, NULL, 4000, 4000, NULL); - if (!pool) - return -1000; - - quit_flag = 0; - - rc = pj_thread_create(pool, "thread", (pj_thread_proc*)&thread_proc, - &counter, - PJ_THREAD_DEFAULT_STACK_SIZE, - flags, - &thread); - - if (rc != PJ_SUCCESS) { - app_perror("...error: unable to create thread", rc); - return -1010; - } - - if (flags & PJ_THREAD_SUSPENDED) { - rc = pj_thread_resume(thread); - if (rc != PJ_SUCCESS) { - app_perror("...error: resume thread error", rc); - return -1020; - } - } - - PJ_LOG(3,(THIS_FILE, "..waiting for thread to quit..")); - - quit_flag = 1; - pj_thread_join(thread); - - pj_pool_release(pool); - - PJ_LOG(3,(THIS_FILE, "...%s success", title)); - return PJ_SUCCESS; -} - - -/* - * timeslice_test() - */ -static int timeslice_test(void) -{ - enum { NUM_THREADS = 4 }; - pj_pool_t *pool; - pj_uint32_t counter[NUM_THREADS], lowest, highest, diff; - pj_thread_t *thread[NUM_THREADS]; - int i; - pj_status_t rc; - - quit_flag = 0; - - pool = pj_pool_create(mem, NULL, 4096, 0, NULL); - if (!pool) - return -10; - - PJ_LOG(3,(THIS_FILE, "..timeslice testing with %d threads", NUM_THREADS)); - - /* Create all threads in suspended mode. */ - for (i=0; i highest) - highest = counter[i]; - } - - /* Check that all threads are running. */ - if (lowest < 2) { - PJ_LOG(3,(THIS_FILE, "...ERROR: not all threads were running!")); - return -70; - } - - /* The difference between lowest and higest should be lower than 50%. - */ - diff = (highest-lowest)*100 / ((highest+lowest)/2); - if ( diff >= 50) { - PJ_LOG(3,(THIS_FILE, "...ERROR: thread didn't have equal timeslice!")); - PJ_LOG(3,(THIS_FILE, ".....lowest counter=%u, highest counter=%u, diff=%u%%", - lowest, highest, diff)); - return -80; - } else { - PJ_LOG(3,(THIS_FILE, - "...info: timeslice diff between lowest & highest=%u%%", - diff)); - } - - return 0; -} - -int thread_test(void) -{ - int rc; - - rc = simple_thread("simple thread test", 0); - if (rc != PJ_SUCCESS) - return rc; - - rc = simple_thread("suspended thread test", PJ_THREAD_SUSPENDED); - if (rc != PJ_SUCCESS) - return rc; - - rc = timeslice_test(); - if (rc != PJ_SUCCESS) - return rc; - - return rc; -} - -#else -/* To prevent warning about "translation unit is empty" - * when this test is disabled. - */ -int dummy_thread_test; -#endif /* INCLUDE_THREAD_TEST */ - - +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/thread.c 4 10/29/05 11:51a Bennylp $ + */ +/* + * $Log: /pjproject-0.3/pjlib/src/pjlib-test/thread.c $ + * + * 4 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 3 14/10/05 11:32 Bennylp + * More lenient with timeslice difference. + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 10/11/05 12:39a Bennylp + * Created. + * + */ +#include "test.h" + +/** + * \page page_pjlib_thread_test Test: Thread Test + * + * This file contains \a thread_test() definition. + * + * \section thread_test_scope_sec Scope of Test + * This tests: + * - whether PJ_THREAD_SUSPENDED flag works. + * - whether multithreading works. + * - whether thread timeslicing works, and threads have equal + * time-slice proportion. + * + * APIs tested: + * - pj_thread_create() + * - pj_thread_register() + * - pj_thread_this() + * - pj_thread_get_name() + * - pj_thread_destroy() + * - pj_thread_resume() + * - pj_thread_sleep() + * - pj_thread_join() + * - pj_thread_destroy() + * + * + * This file is pjlib-test/thread.c + * + * \include pjlib-test/thread.c + */ +#if INCLUDE_THREAD_TEST + +#include + +#define THIS_FILE "thread_test" + +static int quit_flag=0; + +/* + * The thread's entry point. + * + * Each of the thread mainly will just execute the loop which + * increments a variable. + */ +static void* thread_proc(pj_uint32_t *pcounter) +{ + /* Test that pj_thread_register() works. */ + pj_thread_desc desc; + pj_thread_t *this_thread; + pj_status_t rc; + + rc = pj_thread_register("thread", desc, &this_thread); + if (rc != PJ_SUCCESS) { + app_perror("...error in pj_thread_register", rc); + return NULL; + } + + /* Test that pj_thread_this() works */ + this_thread = pj_thread_this(); + if (this_thread == NULL) { + PJ_LOG(3,(THIS_FILE, "...error: pj_thread_this() returns NULL!")); + return NULL; + } + + /* Test that pj_thread_get_name() works */ + if (pj_thread_get_name(this_thread) == NULL) { + PJ_LOG(3,(THIS_FILE, "...error: pj_thread_get_name() returns NULL!")); + return NULL; + } + + /* Main loop */ + for (;!quit_flag;) { + (*pcounter)++; + //Must sleep if platform doesn't do time-slicing. + pj_thread_sleep(0); + } + + return NULL; +} + +/* + * simple_thread() + */ +static int simple_thread(const char *title, unsigned flags) +{ + pj_pool_t *pool; + pj_thread_t *thread; + pj_status_t rc; + pj_uint32_t counter = 0; + + PJ_LOG(3,(THIS_FILE, "..%s", title)); + + pool = pj_pool_create(mem, NULL, 4000, 4000, NULL); + if (!pool) + return -1000; + + quit_flag = 0; + + rc = pj_thread_create(pool, "thread", (pj_thread_proc*)&thread_proc, + &counter, + PJ_THREAD_DEFAULT_STACK_SIZE, + flags, + &thread); + + if (rc != PJ_SUCCESS) { + app_perror("...error: unable to create thread", rc); + return -1010; + } + + if (flags & PJ_THREAD_SUSPENDED) { + rc = pj_thread_resume(thread); + if (rc != PJ_SUCCESS) { + app_perror("...error: resume thread error", rc); + return -1020; + } + } + + PJ_LOG(3,(THIS_FILE, "..waiting for thread to quit..")); + + quit_flag = 1; + pj_thread_join(thread); + + pj_pool_release(pool); + + PJ_LOG(3,(THIS_FILE, "...%s success", title)); + return PJ_SUCCESS; +} + + +/* + * timeslice_test() + */ +static int timeslice_test(void) +{ + enum { NUM_THREADS = 4 }; + pj_pool_t *pool; + pj_uint32_t counter[NUM_THREADS], lowest, highest, diff; + pj_thread_t *thread[NUM_THREADS]; + int i; + pj_status_t rc; + + quit_flag = 0; + + pool = pj_pool_create(mem, NULL, 4096, 0, NULL); + if (!pool) + return -10; + + PJ_LOG(3,(THIS_FILE, "..timeslice testing with %d threads", NUM_THREADS)); + + /* Create all threads in suspended mode. */ + for (i=0; i highest) + highest = counter[i]; + } + + /* Check that all threads are running. */ + if (lowest < 2) { + PJ_LOG(3,(THIS_FILE, "...ERROR: not all threads were running!")); + return -70; + } + + /* The difference between lowest and higest should be lower than 50%. + */ + diff = (highest-lowest)*100 / ((highest+lowest)/2); + if ( diff >= 50) { + PJ_LOG(3,(THIS_FILE, "...ERROR: thread didn't have equal timeslice!")); + PJ_LOG(3,(THIS_FILE, ".....lowest counter=%u, highest counter=%u, diff=%u%%", + lowest, highest, diff)); + return -80; + } else { + PJ_LOG(3,(THIS_FILE, + "...info: timeslice diff between lowest & highest=%u%%", + diff)); + } + + return 0; +} + +int thread_test(void) +{ + int rc; + + rc = simple_thread("simple thread test", 0); + if (rc != PJ_SUCCESS) + return rc; + + rc = simple_thread("suspended thread test", PJ_THREAD_SUSPENDED); + if (rc != PJ_SUCCESS) + return rc; + + rc = timeslice_test(); + if (rc != PJ_SUCCESS) + return rc; + + return rc; +} + +#else +/* To prevent warning about "translation unit is empty" + * when this test is disabled. + */ +int dummy_thread_test; +#endif /* INCLUDE_THREAD_TEST */ + + diff --git a/pjlib/src/pjlib-test/timer.c b/pjlib/src/pjlib-test/timer.c index 1aaa208d..f06b5a01 100644 --- a/pjlib/src/pjlib-test/timer.c +++ b/pjlib/src/pjlib-test/timer.c @@ -1,169 +1,169 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/timer.c 3 10/29/05 10:23p Bennylp $ */ -#include "test.h" - -/** - * \page page_pjlib_timer_test Test: Timer - * - * This file provides implementation of \b timer_test(). It tests the - * functionality of the timer heap. - * - * - * This file is pjlib-test/timer.c - * - * \include pjlib-test/timer.c - */ - - -#if INCLUDE_TIMER_TEST - -#include - -#define LOOP 16 -#define MIN_COUNT 250 -#define MAX_COUNT (LOOP * MIN_COUNT) -#define MIN_DELAY 2 -#define D (MAX_COUNT / 32000) -#define DELAY (D < MIN_DELAY ? MIN_DELAY : D) -#define THIS_FILE "timer_test" - - -static void timer_callback(pj_timer_heap_t *ht, pj_timer_entry *e) -{ - PJ_UNUSED_ARG(ht); - PJ_UNUSED_ARG(e); -} - -static int test_timer_heap(void) -{ - int i, j; - pj_timer_entry *entry; - pj_pool_t *pool; - pj_timer_heap_t *timer; - pj_time_val delay; - pj_status_t rc; int err=0; - unsigned size, count; - - size = pj_timer_heap_mem_size(MAX_COUNT)+MAX_COUNT*sizeof(pj_timer_entry); - pool = pj_pool_create( mem, NULL, size, 4000, NULL); - if (!pool) { - PJ_LOG(3,("test", "...error: unable to create pool of %u bytes", - size)); - return -10; - } - - entry = (pj_timer_entry*)pj_pool_calloc(pool, MAX_COUNT, sizeof(*entry)); - if (!entry) - return -20; - - for (i=0; i 0) { - t_poll.u32.lo += (t2.u32.lo - t1.u32.lo); - early += rc; - } - } - - // Set the time where all timers should finish - pj_gettimeofday(&expire); - delay.sec = DELAY; - delay.msec = 0; - PJ_TIME_VAL_ADD(expire, delay); - - // Wait unfil all timers finish, cancel some of them. - do { - int index = pj_rand() % count; - pj_get_timestamp(&t1); - rc = pj_timer_heap_cancel(timer, &entry[index]); - pj_get_timestamp(&t2); - if (rc > 0) { - cancelled += rc; - t_cancel.u32.lo += (t2.u32.lo - t1.u32.lo); - } - - pj_gettimeofday(&now); - - pj_get_timestamp(&t1); - rc = pj_timer_heap_poll(timer, NULL); - pj_get_timestamp(&t2); - if (rc > 0) { - done += rc; - t_poll.u32.lo += (t2.u32.lo - t1.u32.lo); - } - - } while (PJ_TIME_VAL_LTE(now, expire)&&pj_timer_heap_count(timer) > 0); - - if (pj_timer_heap_count(timer)) { - PJ_LOG(3, (THIS_FILE, "ERROR: %d timers left", - pj_timer_heap_count(timer))); - ++err; - } - t_sched.u32.lo /= count; - t_cancel.u32.lo /= count; - t_poll.u32.lo /= count; - PJ_LOG(4, (THIS_FILE, - "...ok (count:%d, early:%d, cancelled:%d, " - "sched:%d, cancel:%d poll:%d)", - count, early, cancelled, t_sched.u32.lo, t_cancel.u32.lo, - t_poll.u32.lo)); - - count = count * 2; - if (count > MAX_COUNT) - break; - } - - pj_pool_release(pool); - return err; -} - - -int timer_test() -{ - return test_timer_heap(); -} - -#else -/* To prevent warning about "translation unit is empty" - * when this test is disabled. - */ -int dummy_timer_test; -#endif /* INCLUDE_TIMER_TEST */ - - +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/timer.c 3 10/29/05 10:23p Bennylp $ */ +#include "test.h" + +/** + * \page page_pjlib_timer_test Test: Timer + * + * This file provides implementation of \b timer_test(). It tests the + * functionality of the timer heap. + * + * + * This file is pjlib-test/timer.c + * + * \include pjlib-test/timer.c + */ + + +#if INCLUDE_TIMER_TEST + +#include + +#define LOOP 16 +#define MIN_COUNT 250 +#define MAX_COUNT (LOOP * MIN_COUNT) +#define MIN_DELAY 2 +#define D (MAX_COUNT / 32000) +#define DELAY (D < MIN_DELAY ? MIN_DELAY : D) +#define THIS_FILE "timer_test" + + +static void timer_callback(pj_timer_heap_t *ht, pj_timer_entry *e) +{ + PJ_UNUSED_ARG(ht); + PJ_UNUSED_ARG(e); +} + +static int test_timer_heap(void) +{ + int i, j; + pj_timer_entry *entry; + pj_pool_t *pool; + pj_timer_heap_t *timer; + pj_time_val delay; + pj_status_t rc; int err=0; + unsigned size, count; + + size = pj_timer_heap_mem_size(MAX_COUNT)+MAX_COUNT*sizeof(pj_timer_entry); + pool = pj_pool_create( mem, NULL, size, 4000, NULL); + if (!pool) { + PJ_LOG(3,("test", "...error: unable to create pool of %u bytes", + size)); + return -10; + } + + entry = (pj_timer_entry*)pj_pool_calloc(pool, MAX_COUNT, sizeof(*entry)); + if (!entry) + return -20; + + for (i=0; i 0) { + t_poll.u32.lo += (t2.u32.lo - t1.u32.lo); + early += rc; + } + } + + // Set the time where all timers should finish + pj_gettimeofday(&expire); + delay.sec = DELAY; + delay.msec = 0; + PJ_TIME_VAL_ADD(expire, delay); + + // Wait unfil all timers finish, cancel some of them. + do { + int index = pj_rand() % count; + pj_get_timestamp(&t1); + rc = pj_timer_heap_cancel(timer, &entry[index]); + pj_get_timestamp(&t2); + if (rc > 0) { + cancelled += rc; + t_cancel.u32.lo += (t2.u32.lo - t1.u32.lo); + } + + pj_gettimeofday(&now); + + pj_get_timestamp(&t1); + rc = pj_timer_heap_poll(timer, NULL); + pj_get_timestamp(&t2); + if (rc > 0) { + done += rc; + t_poll.u32.lo += (t2.u32.lo - t1.u32.lo); + } + + } while (PJ_TIME_VAL_LTE(now, expire)&&pj_timer_heap_count(timer) > 0); + + if (pj_timer_heap_count(timer)) { + PJ_LOG(3, (THIS_FILE, "ERROR: %d timers left", + pj_timer_heap_count(timer))); + ++err; + } + t_sched.u32.lo /= count; + t_cancel.u32.lo /= count; + t_poll.u32.lo /= count; + PJ_LOG(4, (THIS_FILE, + "...ok (count:%d, early:%d, cancelled:%d, " + "sched:%d, cancel:%d poll:%d)", + count, early, cancelled, t_sched.u32.lo, t_cancel.u32.lo, + t_poll.u32.lo)); + + count = count * 2; + if (count > MAX_COUNT) + break; + } + + pj_pool_release(pool); + return err; +} + + +int timer_test() +{ + return test_timer_heap(); +} + +#else +/* To prevent warning about "translation unit is empty" + * when this test is disabled. + */ +int dummy_timer_test; +#endif /* INCLUDE_TIMER_TEST */ + + diff --git a/pjlib/src/pjlib-test/timestamp.c b/pjlib/src/pjlib-test/timestamp.c index 3d4d9f8e..4dac0db1 100644 --- a/pjlib/src/pjlib-test/timestamp.c +++ b/pjlib/src/pjlib-test/timestamp.c @@ -1,140 +1,143 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/timestamp.c 4 10/29/05 11:51a Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pjlib-test/timestamp.c $ - * - * 4 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 3 14/10/05 11:32 Bennylp - * Longer test, to check if timestamp is running backwards. - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 10/09/05 9:39p Bennylp - * Created. - * - */ -#include "test.h" -#include -#include - - -/** - * \page page_pjlib_timestamp_test Test: Timestamp - * - * This file provides implementation of timestamp_test() - * - * \section timestamp_test_sec Scope of the Test - * - * This tests whether timestamp API works. - * - * API tested: - * - pj_get_timestamp_freq() - * - pj_get_timestamp() - * - pj_elapsed_usec() - * - PJ_LOG() - * - * - * This file is pjlib-test/timestamp.c - * - * \include pjlib-test/timestamp.c - */ - -#if INCLUDE_TIMESTAMP_TEST - -#define THIS_FILE "timestamp" - -int timestamp_test(void) -{ - enum { CONSECUTIVE_LOOP = 1000 }; - volatile unsigned i; - pj_timestamp freq, t1, t2; - unsigned elapsed; - pj_status_t rc; - - PJ_LOG(3,(THIS_FILE, "...Testing timestamp (high res time)")); - - /* Get and display timestamp frequency. */ - if ((rc=pj_get_timestamp_freq(&freq)) != PJ_SUCCESS) { - app_perror("...ERROR: get timestamp freq", rc); - return -1000; - } - - PJ_LOG(3,(THIS_FILE, "....frequency: hiword=%lu loword=%lu", - freq.u32.hi, freq.u32.lo)); - - PJ_LOG(3,(THIS_FILE, "...checking if time can run backwards (pls wait)..")); - - /* - * Check if consecutive readings should yield timestamp value - * that is bigger than previous value. - * First we get the first timestamp. - */ - rc = pj_get_timestamp(&t1); - if (rc != PJ_SUCCESS) { - app_perror("...ERROR: get timestamp", rc); - return -1001; - } - for (i=0; i= t1. */ - if (t2.u32.hi < t1.u32.hi || - (t2.u32.hi == t1.u32.hi && t2.u32.lo < t1.u32.lo)) - { - PJ_LOG(3,(THIS_FILE, "...ERROR: timestamp runs backwards!")); - return -1003; - } - } - - /* - * Simple test to time some loop. - */ - PJ_LOG(3,(THIS_FILE, "....testing simple 1000000 loop")); - - - /* Mark start time. */ - if ((rc=pj_get_timestamp(&t1)) != PJ_SUCCESS) { - app_perror("....error: cat't get timestamp", rc); - return -1010; - } - - /* Loop.. */ - for (i=0; i<1000000; ++i) - ; - - /* Mark end time. */ - pj_get_timestamp(&t2); - - /* Get elapsed time in usec. */ - elapsed = pj_elapsed_usec(&t1, &t2); - PJ_LOG(3,(THIS_FILE, "....elapsed: %u usec", (unsigned)elapsed)); - - /* See if elapsed time is reasonable. */ - if (elapsed < 1 || elapsed > 100000) { - PJ_LOG(3,(THIS_FILE, "....error: elapsed time outside window (%u)", - elapsed)); - return -1030; - } - return 0; -} - - -#else -/* To prevent warning about "translation unit is empty" - * when this test is disabled. - */ -int dummy_timestamp_test; -#endif /* INCLUDE_TIMESTAMP_TEST */ - +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/timestamp.c 4 10/29/05 11:51a Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pjlib-test/timestamp.c $ + * + * 4 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 3 14/10/05 11:32 Bennylp + * Longer test, to check if timestamp is running backwards. + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 10/09/05 9:39p Bennylp + * Created. + * + */ +#include "test.h" +#include +#include + + +/** + * \page page_pjlib_timestamp_test Test: Timestamp + * + * This file provides implementation of timestamp_test() + * + * \section timestamp_test_sec Scope of the Test + * + * This tests whether timestamp API works. + * + * API tested: + * - pj_get_timestamp_freq() + * - pj_get_timestamp() + * - pj_elapsed_usec() + * - PJ_LOG() + * + * + * This file is pjlib-test/timestamp.c + * + * \include pjlib-test/timestamp.c + */ + +#if INCLUDE_TIMESTAMP_TEST + +#define THIS_FILE "timestamp" + +int timestamp_test(void) +{ + enum { CONSECUTIVE_LOOP = 1000 }; + volatile unsigned i; + pj_timestamp freq, t1, t2; + unsigned elapsed; + pj_status_t rc; + + PJ_LOG(3,(THIS_FILE, "...Testing timestamp (high res time)")); + + /* Get and display timestamp frequency. */ + if ((rc=pj_get_timestamp_freq(&freq)) != PJ_SUCCESS) { + app_perror("...ERROR: get timestamp freq", rc); + return -1000; + } + + PJ_LOG(3,(THIS_FILE, "....frequency: hiword=%lu loword=%lu", + freq.u32.hi, freq.u32.lo)); + + PJ_LOG(3,(THIS_FILE, "...checking if time can run backwards (pls wait)..")); + + /* + * Check if consecutive readings should yield timestamp value + * that is bigger than previous value. + * First we get the first timestamp. + */ + rc = pj_get_timestamp(&t1); + if (rc != PJ_SUCCESS) { + app_perror("...ERROR: get timestamp", rc); + return -1001; + } + for (i=0; i= t1. */ + if (t2.u32.hi < t1.u32.hi || + (t2.u32.hi == t1.u32.hi && t2.u32.lo < t1.u32.lo)) + { + PJ_LOG(3,(THIS_FILE, "...ERROR: timestamp runs backwards!")); + return -1003; + } + } + + /* + * Simple test to time some loop. + */ + PJ_LOG(3,(THIS_FILE, "....testing simple 1000000 loop")); + + + /* Mark start time. */ + if ((rc=pj_get_timestamp(&t1)) != PJ_SUCCESS) { + app_perror("....error: cat't get timestamp", rc); + return -1010; + } + + /* Loop.. */ + for (i=0; i<1000000; ++i) + ; + + /* Mark end time. */ + pj_get_timestamp(&t2); + + /* Get elapsed time in usec. */ + elapsed = pj_elapsed_usec(&t1, &t2); + PJ_LOG(3,(THIS_FILE, "....elapsed: %u usec", (unsigned)elapsed)); + + /* See if elapsed time is reasonable. */ + if (elapsed < 1 || elapsed > 100000) { + PJ_LOG(3,(THIS_FILE, "....error: elapsed time outside window (%u, " + "t1.u32.hi=%u, t1.u32.lo=%u, " + "t2.u32.hi=%u, t2.u32.lo=%u)", + elapsed, + t1.u32.hi, t1.u32.lo, t2.u32.hi, t2.u32.lo)); + return -1030; + } + return 0; +} + + +#else +/* To prevent warning about "translation unit is empty" + * when this test is disabled. + */ +int dummy_timestamp_test; +#endif /* INCLUDE_TIMESTAMP_TEST */ + diff --git a/pjlib/src/pjlib-test/udp_echo_srv_sync.c b/pjlib/src/pjlib-test/udp_echo_srv_sync.c index b513498b..b95eb61e 100644 --- a/pjlib/src/pjlib-test/udp_echo_srv_sync.c +++ b/pjlib/src/pjlib-test/udp_echo_srv_sync.c @@ -1,168 +1,168 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/udp_echo_srv_sync.c 2 29/10/05 21:34 Bennylp $ */ -/* - * $Log: /pjproject-0.3/pjlib/src/pjlib-test/udp_echo_srv_sync.c $ - * - * 2 29/10/05 21:34 Bennylp - * Tested on Win32 - * - * 1 10/29/05 9:56a Bennylp - * Created. - * - */ -#include "test.h" -#include - -static pj_sem_t *sem; -static pj_mutex_t *mutex; -static pj_size_t total_bw; - -static int worker_thread(void *arg) -{ - pj_sock_t sock = (pj_sock_t)arg; - char buf[1516]; - pj_size_t received; - pj_time_val last_print; - pj_status_t last_recv_err = PJ_SUCCESS, last_write_err = PJ_SUCCESS; - - received = 0; - pj_gettimeofday(&last_print); - - for (;;) { - pj_ssize_t len; - pj_uint32_t delay_msec; - pj_time_val now; - pj_highprec_t bw; - pj_status_t rc; - pj_sockaddr_in addr; - int addrlen; - - len = sizeof(buf); - addrlen = sizeof(addr); - rc = pj_sock_recvfrom(sock, buf, &len, 0, &addr, &addrlen); - if (rc != 0) { - if (rc != last_recv_err) { - app_perror("...recv error", rc); - last_recv_err = rc; - } - continue; - } - - received += len; - - rc = pj_sock_sendto(sock, buf, &len, 0, &addr, addrlen); - if (rc != PJ_SUCCESS) { - if (rc != last_write_err) { - app_perror("...send error", rc); - last_write_err = rc; - } - continue; - } - - pj_gettimeofday(&now); - PJ_TIME_VAL_SUB(now, last_print); - delay_msec = PJ_TIME_VAL_MSEC(now); - - if (delay_msec < 1000) - continue; - - bw = received; - pj_highprec_mul(bw, 1000); - pj_highprec_div(bw, delay_msec); - - pj_mutex_lock(mutex); - total_bw = total_bw + (pj_size_t)bw; - pj_mutex_unlock(mutex); - - pj_gettimeofday(&last_print); - received = 0; - pj_sem_post(sem); - pj_thread_sleep(0); - } -} - - -int echo_srv_sync(void) -{ - pj_pool_t *pool; - pj_sock_t sock; - pj_thread_t *thread[ECHO_SERVER_MAX_THREADS]; - pj_status_t rc; - pj_highprec_t abs_total; - unsigned count; - int i; - - pool = pj_pool_create(mem, NULL, 4000, 4000, NULL); - if (!pool) - return -5; - - rc = pj_sem_create(pool, NULL, 0, ECHO_SERVER_MAX_THREADS, &sem); - if (rc != PJ_SUCCESS) { - app_perror("...unable to create semaphore", rc); - return -6; - } - - rc = pj_mutex_create_simple(pool, NULL, &mutex); - if (rc != PJ_SUCCESS) { - app_perror("...unable to create mutex", rc); - return -7; - } - - rc = app_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, ECHO_SERVER_START_PORT, &sock); - if (rc != PJ_SUCCESS) { - app_perror("...socket error", rc); - return -10; - } - - for (i=0; i" : ""))); - - total_bw = 0; - - if (count==20) { - count = 0; - abs_total = 0; - } - - while (pj_sem_trywait(sem) == PJ_SUCCESS) - ; - } -} - - +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/udp_echo_srv_sync.c 2 29/10/05 21:34 Bennylp $ */ +/* + * $Log: /pjproject-0.3/pjlib/src/pjlib-test/udp_echo_srv_sync.c $ + * + * 2 29/10/05 21:34 Bennylp + * Tested on Win32 + * + * 1 10/29/05 9:56a Bennylp + * Created. + * + */ +#include "test.h" +#include + +static pj_sem_t *sem; +static pj_mutex_t *mutex; +static pj_size_t total_bw; + +static int worker_thread(void *arg) +{ + pj_sock_t sock = (pj_sock_t)arg; + char buf[1516]; + pj_size_t received; + pj_time_val last_print; + pj_status_t last_recv_err = PJ_SUCCESS, last_write_err = PJ_SUCCESS; + + received = 0; + pj_gettimeofday(&last_print); + + for (;;) { + pj_ssize_t len; + pj_uint32_t delay_msec; + pj_time_val now; + pj_highprec_t bw; + pj_status_t rc; + pj_sockaddr_in addr; + int addrlen; + + len = sizeof(buf); + addrlen = sizeof(addr); + rc = pj_sock_recvfrom(sock, buf, &len, 0, &addr, &addrlen); + if (rc != 0) { + if (rc != last_recv_err) { + app_perror("...recv error", rc); + last_recv_err = rc; + } + continue; + } + + received += len; + + rc = pj_sock_sendto(sock, buf, &len, 0, &addr, addrlen); + if (rc != PJ_SUCCESS) { + if (rc != last_write_err) { + app_perror("...send error", rc); + last_write_err = rc; + } + continue; + } + + pj_gettimeofday(&now); + PJ_TIME_VAL_SUB(now, last_print); + delay_msec = PJ_TIME_VAL_MSEC(now); + + if (delay_msec < 1000) + continue; + + bw = received; + pj_highprec_mul(bw, 1000); + pj_highprec_div(bw, delay_msec); + + pj_mutex_lock(mutex); + total_bw = total_bw + (pj_size_t)bw; + pj_mutex_unlock(mutex); + + pj_gettimeofday(&last_print); + received = 0; + pj_sem_post(sem); + pj_thread_sleep(0); + } +} + + +int echo_srv_sync(void) +{ + pj_pool_t *pool; + pj_sock_t sock; + pj_thread_t *thread[ECHO_SERVER_MAX_THREADS]; + pj_status_t rc; + pj_highprec_t abs_total; + unsigned count; + int i; + + pool = pj_pool_create(mem, NULL, 4000, 4000, NULL); + if (!pool) + return -5; + + rc = pj_sem_create(pool, NULL, 0, ECHO_SERVER_MAX_THREADS, &sem); + if (rc != PJ_SUCCESS) { + app_perror("...unable to create semaphore", rc); + return -6; + } + + rc = pj_mutex_create_simple(pool, NULL, &mutex); + if (rc != PJ_SUCCESS) { + app_perror("...unable to create mutex", rc); + return -7; + } + + rc = app_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, ECHO_SERVER_START_PORT, &sock); + if (rc != PJ_SUCCESS) { + app_perror("...socket error", rc); + return -10; + } + + for (i=0; i" : ""))); + + total_bw = 0; + + if (count==20) { + count = 0; + abs_total = 0; + } + + while (pj_sem_trywait(sem) == PJ_SUCCESS) + ; + } +} + + diff --git a/pjlib/src/pjlib-test/util.c b/pjlib/src/pjlib-test/util.c index c698cff4..991d8ddb 100644 --- a/pjlib/src/pjlib-test/util.c +++ b/pjlib/src/pjlib-test/util.c @@ -1,129 +1,129 @@ -/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/util.c 3 10/29/05 11:51a Bennylp $ - */ -/* - * $Log: /pjproject-0.3/pjlib/src/pjlib-test/util.c $ - * - * 3 10/29/05 11:51a Bennylp - * Version 0.3-pre2. - * - * 2 10/14/05 12:26a Bennylp - * Finished error code framework, some fixes in ioqueue, etc. Pretty - * major. - * - * 1 10/12/05 10:00a Bennylp - * Created. - * - */ -#include "test.h" -#include - -void app_perror(const char *msg, pj_status_t rc) -{ - char errbuf[256]; - - PJ_CHECK_STACK(); - - pj_strerror(rc, errbuf, sizeof(errbuf)); - PJ_LOG(1,("test", "%s: [pj_status_t=%d] %s", msg, rc, errbuf)); -} - -#define SERVER 0 -#define CLIENT 1 - -pj_status_t app_socket(int family, int type, int proto, int port, - pj_sock_t *ptr_sock) -{ - pj_sockaddr_in addr; - pj_sock_t sock; - pj_status_t rc; - - rc = pj_sock_socket(family, type, proto, &sock); - if (rc != PJ_SUCCESS) - return rc; - - pj_memset(&addr, 0, sizeof(addr)); - addr.sin_family = (pj_uint16_t)family; - addr.sin_port = (short)(port!=-1 ? pj_htons((pj_uint16_t)port) : 0); - rc = pj_sock_bind(sock, &addr, sizeof(addr)); - if (rc != PJ_SUCCESS) - return rc; - - if (type == PJ_SOCK_STREAM) { - rc = pj_sock_listen(sock, 5); - if (rc != PJ_SUCCESS) - return rc; - } - - *ptr_sock = sock; - return PJ_SUCCESS; -} - -pj_status_t app_socketpair(int family, int type, int protocol, - pj_sock_t *serverfd, pj_sock_t *clientfd) -{ - int i; - static unsigned short port = 11000; - pj_sockaddr_in addr; - pj_str_t s; - pj_status_t rc = 0; - pj_sock_t sock[2]; - - /* Create both sockets. */ - for (i=0; i<2; ++i) { - rc = pj_sock_socket(family, type, protocol, &sock[i]); - if (rc != PJ_SUCCESS) { - if (i==1) - pj_sock_close(sock[0]); - return rc; - } - } - - /* Retry bind */ - pj_memset(&addr, 0, sizeof(addr)); - addr.sin_family = PJ_AF_INET; - for (i=0; i<5; ++i) { - addr.sin_port = pj_htons(port++); - rc = pj_sock_bind(sock[SERVER], &addr, sizeof(addr)); - if (rc == PJ_SUCCESS) - break; - } - - if (rc != PJ_SUCCESS) - goto on_error; - - /* For TCP, listen the socket. */ - if (type == PJ_SOCK_STREAM) { - rc = pj_sock_listen(sock[SERVER], PJ_SOMAXCONN); - if (rc != PJ_SUCCESS) - goto on_error; - } - - /* Connect client socket. */ - addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1")); - rc = pj_sock_connect(sock[CLIENT], &addr, sizeof(addr)); - if (rc != PJ_SUCCESS) - goto on_error; - - /* For TCP, must accept(), and get the new socket. */ - if (type == PJ_SOCK_STREAM) { - pj_sock_t newserver; - - rc = pj_sock_accept(sock[SERVER], &newserver, NULL, NULL); - if (rc != PJ_SUCCESS) - goto on_error; - - /* Replace server socket with new socket. */ - pj_sock_close(sock[SERVER]); - sock[SERVER] = newserver; - } - - *serverfd = sock[SERVER]; - *clientfd = sock[CLIENT]; - - return rc; - -on_error: - for (i=0; i<2; ++i) - pj_sock_close(sock[i]); - return rc; -} +/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/util.c 3 10/29/05 11:51a Bennylp $ + */ +/* + * $Log: /pjproject-0.3/pjlib/src/pjlib-test/util.c $ + * + * 3 10/29/05 11:51a Bennylp + * Version 0.3-pre2. + * + * 2 10/14/05 12:26a Bennylp + * Finished error code framework, some fixes in ioqueue, etc. Pretty + * major. + * + * 1 10/12/05 10:00a Bennylp + * Created. + * + */ +#include "test.h" +#include + +void app_perror(const char *msg, pj_status_t rc) +{ + char errbuf[256]; + + PJ_CHECK_STACK(); + + pj_strerror(rc, errbuf, sizeof(errbuf)); + PJ_LOG(1,("test", "%s: [pj_status_t=%d] %s", msg, rc, errbuf)); +} + +#define SERVER 0 +#define CLIENT 1 + +pj_status_t app_socket(int family, int type, int proto, int port, + pj_sock_t *ptr_sock) +{ + pj_sockaddr_in addr; + pj_sock_t sock; + pj_status_t rc; + + rc = pj_sock_socket(family, type, proto, &sock); + if (rc != PJ_SUCCESS) + return rc; + + pj_memset(&addr, 0, sizeof(addr)); + addr.sin_family = (pj_uint16_t)family; + addr.sin_port = (short)(port!=-1 ? pj_htons((pj_uint16_t)port) : 0); + rc = pj_sock_bind(sock, &addr, sizeof(addr)); + if (rc != PJ_SUCCESS) + return rc; + + if (type == PJ_SOCK_STREAM) { + rc = pj_sock_listen(sock, 5); + if (rc != PJ_SUCCESS) + return rc; + } + + *ptr_sock = sock; + return PJ_SUCCESS; +} + +pj_status_t app_socketpair(int family, int type, int protocol, + pj_sock_t *serverfd, pj_sock_t *clientfd) +{ + int i; + static unsigned short port = 11000; + pj_sockaddr_in addr; + pj_str_t s; + pj_status_t rc = 0; + pj_sock_t sock[2]; + + /* Create both sockets. */ + for (i=0; i<2; ++i) { + rc = pj_sock_socket(family, type, protocol, &sock[i]); + if (rc != PJ_SUCCESS) { + if (i==1) + pj_sock_close(sock[0]); + return rc; + } + } + + /* Retry bind */ + pj_memset(&addr, 0, sizeof(addr)); + addr.sin_family = PJ_AF_INET; + for (i=0; i<5; ++i) { + addr.sin_port = pj_htons(port++); + rc = pj_sock_bind(sock[SERVER], &addr, sizeof(addr)); + if (rc == PJ_SUCCESS) + break; + } + + if (rc != PJ_SUCCESS) + goto on_error; + + /* For TCP, listen the socket. */ + if (type == PJ_SOCK_STREAM) { + rc = pj_sock_listen(sock[SERVER], PJ_SOMAXCONN); + if (rc != PJ_SUCCESS) + goto on_error; + } + + /* Connect client socket. */ + addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1")); + rc = pj_sock_connect(sock[CLIENT], &addr, sizeof(addr)); + if (rc != PJ_SUCCESS) + goto on_error; + + /* For TCP, must accept(), and get the new socket. */ + if (type == PJ_SOCK_STREAM) { + pj_sock_t newserver; + + rc = pj_sock_accept(sock[SERVER], &newserver, NULL, NULL); + if (rc != PJ_SUCCESS) + goto on_error; + + /* Replace server socket with new socket. */ + pj_sock_close(sock[SERVER]); + sock[SERVER] = newserver; + } + + *serverfd = sock[SERVER]; + *clientfd = sock[CLIENT]; + + return rc; + +on_error: + for (i=0; i<2; ++i) + pj_sock_close(sock[i]); + return rc; +} diff --git a/pjlib/src/pjlib-test/xml.c b/pjlib/src/pjlib-test/xml.c index 9a7c0a1e..da954489 100644 --- a/pjlib/src/pjlib-test/xml.c +++ b/pjlib/src/pjlib-test/xml.c @@ -1,127 +1,127 @@ -#include "test.h" - - -#if INCLUDE_XML_TEST - -#include -#include - -#define THIS_FILE "xml_test" - -static const char *xml_doc[] = -{ -" \n" -" \n" -"\n" -" \n" -" \n" -" open\n" -" assistant\n" -" \n" -" \n" -" true\n" -" false\n" -" true\n" -" \n" -" tel:09012345678\n" -" \n" -"\n" -" \n" -" \n" -" open\n" -" \n" -" im:pep@example.com\n" -" \n" -"\n" -" \n" -" \n" -" closed\n" -" meeting\n" -" \n" -" http://example.com/~pep/\n" -" http://example.com/~pep/icon.gif\n" -" http://example.com/~pep/card.vcd\n" -" sip:pep@example.com\n" -" \n" -"\n" -" Full state presence document\n" -"\n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -"\n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -"\n" -" \n" -} -; - -static int xml_parse_print_test(const char *doc) -{ - pj_str_t msg; - pj_pool_t *pool; - pj_xml_node *root; - char *output; - int output_len; - - pool = pj_pool_create(mem, "xml", 4096, 1024, NULL); - pj_strdup2(pool, &msg, doc); - root = pj_xml_parse(pool, msg.ptr, msg.slen); - if (!root) { - PJ_LOG(1, (THIS_FILE, " Error: unable to parse XML")); - return -10; - } - - output = (char*)pj_pool_alloc(pool, msg.slen + 512); - pj_memset(output, 0, msg.slen+512); - output_len = pj_xml_print(root, output, msg.slen+512, PJ_TRUE); - if (output_len < 1) { - PJ_LOG(1, (THIS_FILE, " Error: buffer too small to print XML file")); - return -20; - } - output[output_len] = '\0'; - - - pj_pool_release(pool); - return 0; -} - -int xml_test() -{ - unsigned i; - for (i=0; i +#include + +#define THIS_FILE "xml_test" + +static const char *xml_doc[] = +{ +" \n" +" \n" +"\n" +" \n" +" \n" +" open\n" +" assistant\n" +" \n" +" \n" +" true\n" +" false\n" +" true\n" +" \n" +" tel:09012345678\n" +" \n" +"\n" +" \n" +" \n" +" open\n" +" \n" +" im:pep@example.com\n" +" \n" +"\n" +" \n" +" \n" +" closed\n" +" meeting\n" +" \n" +" http://example.com/~pep/\n" +" http://example.com/~pep/icon.gif\n" +" http://example.com/~pep/card.vcd\n" +" sip:pep@example.com\n" +" \n" +"\n" +" Full state presence document\n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" +" \n" +} +; + +static int xml_parse_print_test(const char *doc) +{ + pj_str_t msg; + pj_pool_t *pool; + pj_xml_node *root; + char *output; + int output_len; + + pool = pj_pool_create(mem, "xml", 4096, 1024, NULL); + pj_strdup2(pool, &msg, doc); + root = pj_xml_parse(pool, msg.ptr, msg.slen); + if (!root) { + PJ_LOG(1, (THIS_FILE, " Error: unable to parse XML")); + return -10; + } + + output = (char*)pj_pool_alloc(pool, msg.slen + 512); + pj_memset(output, 0, msg.slen+512); + output_len = pj_xml_print(root, output, msg.slen+512, PJ_TRUE); + if (output_len < 1) { + PJ_LOG(1, (THIS_FILE, " Error: buffer too small to print XML file")); + return -20; + } + output[output_len] = '\0'; + + + pj_pool_release(pool); + return 0; +} + +int xml_test() +{ + unsigned i; + for (i=0; i