Initial commit.
authorAndreas Schneider <asn@cryptomilk.org>
Tue, 5 Feb 2013 16:18:31 +0000 (17:18 +0100)
committerAndreas Schneider <asn@cryptomilk.org>
Thu, 7 Feb 2013 15:58:18 +0000 (16:58 +0100)
21 files changed:
CMakeLists.txt [new file with mode: 0644]
COPYING [new file with mode: 0644]
CPackConfig.cmake [new file with mode: 0644]
CTestConfig.cmake [new file with mode: 0644]
ConfigureChecks.cmake [new file with mode: 0644]
DefineOptions.cmake [new file with mode: 0644]
README [new file with mode: 0644]
cmake/Modules/COPYING-CMAKE-SCRIPTS [new file with mode: 0644]
cmake/Modules/CheckCCompilerFlagSSP.cmake [new file with mode: 0644]
cmake/Modules/DefineCMakeDefaults.cmake [new file with mode: 0644]
cmake/Modules/DefineCompilerFlags.cmake [new file with mode: 0644]
cmake/Modules/DefineInstallationPaths.cmake [new file with mode: 0644]
cmake/Modules/DefinePlatformDefaults.cmake [new file with mode: 0644]
cmake/Modules/MacroEnsureOutOfSourceBuild.cmake [new file with mode: 0644]
config.h.cmake [new file with mode: 0644]
src/CMakeLists.txt [new file with mode: 0644]
src/py_socket_wrapper.c [new file with mode: 0644]
src/socket.py [new file with mode: 0644]
src/socket_wrapper.c [new file with mode: 0644]
src/socket_wrapper.h [new file with mode: 0644]
tests/testsuite.c [new file with mode: 0644]

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c047947
--- /dev/null
@@ -0,0 +1,51 @@
+project(socket_wrapper C)
+
+# Required cmake version
+cmake_minimum_required(VERSION 2.8.0)
+
+# global needed variables
+set(APPLICATION_NAME ${PROJECT_NAME})
+
+set(APPLICATION_VERSION_MAJOR "0")
+set(APPLICATION_VERSION_MINOR "1")
+set(APPLICATION_VERSION_PATCH "0")
+
+set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}")
+
+# SOVERSION scheme: CURRENT.AGE.REVISION
+#   If there was an incompatible interface change:
+#     Increment CURRENT. Set AGE and REVISION to 0
+#   If there was a compatible interface change:
+#     Increment AGE. Set REVISION to 0
+#   If the source code was changed, but there were no interface changes:
+#     Increment REVISION.
+set(LIBRARY_VERSION "0.0.1")
+set(LIBRARY_SOVERSION "0")
+
+# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
+set(CMAKE_MODULE_PATH
+  ${CMAKE_SOURCE_DIR}/cmake/Modules
+)
+
+# add definitions
+include(DefineCMakeDefaults)
+include(DefinePlatformDefaults)
+include(DefineCompilerFlags)
+include(DefineInstallationPaths)
+include(DefineOptions.cmake)
+include(CPackConfig.cmake)
+
+# disallow in-source build
+include(MacroEnsureOutOfSourceBuild)
+macro_ensure_out_of_source_build("${PROJECT_NAME} requires an out of source build. Please create a separate build directory and run 'cmake /path/to/${PROJECT_NAME} [options]' there.")
+
+# Find out if we have threading available
+set(CMAKE_THREAD_PREFER_PTHREADS ON)
+find_package(Threads)
+
+# config.h checks
+include(ConfigureChecks.cmake)
+configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+
+# check subdirectories
+add_subdirectory(src)
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..e6227e1
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,32 @@
+Copyright (C) Jelmer Vernooij 2005,2008 <jelmer@samba.org>
+Copyright (C) Stefan Metzmacher 2006-2009 <metze@samba.org>
+Copyright (C) Andreas Schneider 2013 <asn@samba.org>
+
+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. Neither the name of the author 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 AUTHOR 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 AUTHOR 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/CPackConfig.cmake b/CPackConfig.cmake
new file mode 100644 (file)
index 0000000..2e4c9fe
--- /dev/null
@@ -0,0 +1,53 @@
+# For help take a look at:
+# http://www.cmake.org/Wiki/CMake:CPackConfiguration
+
+### general settings
+set(CPACK_PACKAGE_NAME ${APPLICATION_NAME})
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The SSH library")
+set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README")
+set(CPACK_PACKAGE_VENDOR "The SSH Library Development Team")
+set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME})
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING")
+
+
+### versions
+set(CPACK_PACKAGE_VERSION_MAJOR "0")
+set(CPACK_PACKAGE_VERSION_MINOR "5")
+set(CPACK_PACKAGE_VERSION_PATCH "90")
+set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
+
+
+### source generator
+set(CPACK_SOURCE_GENERATOR "TGZ")
+set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build/;tags;cscope.*")
+set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
+
+if (WIN32)
+    set(CPACK_GENERATOR "ZIP")
+
+    ### nsis generator
+    find_package(NSIS)
+    if (NSIS_MAKE)
+        set(CPACK_GENERATOR "${CPACK_GENERATOR};NSIS")
+        set(CPACK_NSIS_DISPLAY_NAME "The SSH Library")
+        set(CPACK_NSIS_COMPRESSOR "/SOLID zlib")
+        set(CPACK_NSIS_MENU_LINKS "http://www.libssh.org/" "libssh homepage")
+    endif (NSIS_MAKE)
+endif (WIN32)
+
+set(CPACK_PACKAGE_INSTALL_DIRECTORY "libssh")
+
+set(CPACK_PACKAGE_FILE_NAME ${APPLICATION_NAME}-${CPACK_PACKAGE_VERSION})
+
+set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries")
+set(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "C/C++ Headers")
+set(CPACK_COMPONENT_LIBRARIES_DESCRIPTION
+  "Libraries used to build programs which use libssh")
+set(CPACK_COMPONENT_HEADERS_DESCRIPTION
+  "C/C++ header files for use with libssh")
+set(CPACK_COMPONENT_HEADERS_DEPENDS libraries)
+#set(CPACK_COMPONENT_APPLICATIONS_GROUP "Runtime")
+set(CPACK_COMPONENT_LIBRARIES_GROUP "Development")
+set(CPACK_COMPONENT_HEADERS_GROUP "Development")
+
+include(CPack)
diff --git a/CTestConfig.cmake b/CTestConfig.cmake
new file mode 100644 (file)
index 0000000..d8a4183
--- /dev/null
@@ -0,0 +1,9 @@
+set(UPDATE_TYPE "true")
+
+set(CTEST_PROJECT_NAME "libssh")
+set(CTEST_NIGHTLY_START_TIME "01:00:00 CET")
+
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "test.libssh.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=libssh")
+set(CTEST_DROP_SITE_CDASH TRUE)
diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake
new file mode 100644 (file)
index 0000000..6cb45d0
--- /dev/null
@@ -0,0 +1,100 @@
+include(CheckIncludeFile)
+include(CheckSymbolExists)
+include(CheckFunctionExists)
+include(CheckLibraryExists)
+include(CheckTypeSize)
+include(CheckStructHasMember)
+include(CheckPrototypeDefinition)
+include(TestBigEndian)
+
+set(PACKAGE ${APPLICATION_NAME})
+set(VERSION ${APPLICATION_VERSION})
+set(DATADIR ${DATA_INSTALL_DIR})
+set(LIBDIR ${LIB_INSTALL_DIR})
+set(PLUGINDIR "${PLUGIN_INSTALL_DIR}-${LIBRARY_SOVERSION}")
+set(SYSCONFDIR ${SYSCONF_INSTALL_DIR})
+
+set(BINARYDIR ${CMAKE_BINARY_DIR})
+set(SOURCEDIR ${CMAKE_SOURCE_DIR})
+
+function(COMPILER_DUMPVERSION _OUTPUT_VERSION)
+    # Remove whitespaces from the argument.
+    # This is needed for CC="ccache gcc" cmake ..
+    string(REPLACE " " "" _C_COMPILER_ARG "${CMAKE_C_COMPILER_ARG1}")
+
+    execute_process(
+        COMMAND
+            ${CMAKE_C_COMPILER} ${_C_COMPILER_ARG} -dumpversion
+        OUTPUT_VARIABLE _COMPILER_VERSION
+    )
+
+    string(REGEX REPLACE "([0-9])\\.([0-9])(\\.[0-9])?" "\\1\\2"
+           _COMPILER_VERSION "${_COMPILER_VERSION}")
+
+    set(${_OUTPUT_VERSION} ${_COMPILER_VERSION} PARENT_SCOPE)
+endfunction()
+
+if(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2)
+    compiler_dumpversion(GNUCC_VERSION)
+    if (NOT GNUCC_VERSION EQUAL 34)
+        set(CMAKE_REQUIRED_FLAGS "-fvisibility=hidden")
+        check_c_source_compiles(
+"void __attribute__((visibility(\"default\"))) test() {}
+int main(void){ return 0; }
+" WITH_VISIBILITY_HIDDEN)
+        set(CMAKE_REQUIRED_FLAGS "")
+    endif (NOT GNUCC_VERSION EQUAL 34)
+endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2)
+
+# HEADERS
+check_include_file(sys/filio.h HAVE_SYS_FILIO_H)
+
+# FUNCTIONS
+check_function_exists(strncpy HAVE_STRNCPY)
+check_function_exists(vsnprintf HAVE_VSNPRINTF)
+check_function_exists(snprintf HAVE_SNPRINTF)
+
+if (WIN32)
+    check_function_exists(_vsnprintf_s HAVE__VSNPRINTF_S)
+    check_function_exists(_vsnprintf HAVE__VSNPRINTF)
+    check_function_exists(_snprintf HAVE__SNPRINTF)
+    check_function_exists(_snprintf_s HAVE__SNPRINTF_S)
+endif (WIN32)
+
+if (UNIX)
+    if (NOT LINUX)
+        # libsocket (Solaris)
+        check_library_exists(socket getaddrinfo "" HAVE_LIBSOCKET)
+        if (HAVE_LIBSOCKET)
+          set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} socket)
+        endif (HAVE_LIBSOCKET)
+
+        # libnsl/inet_pton (Solaris)
+        check_library_exists(nsl inet_pton "" HAVE_LIBNSL)
+        if (HAVE_LIBNSL)
+            set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} nsl)
+        endif (HAVE_LIBNSL)
+    endif (NOT LINUX)
+
+    check_function_exists(getaddrinfo HAVE_GETADDRINFO)
+endif (UNIX)
+
+set(LIBSSH_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CACHE INTERNAL "libssh required system libraries")
+
+# STRUCT MEMBERS
+check_struct_has_member("struct sockaddr" sa_len "sys/socket.h netinet/in.h" HAVE_STRUCT_SOCKADDR_SA_LEN)
+
+# PROTOTYPES
+check_prototype_definition(gettimeofday
+    "int gettimeofday(struct timeval *tv, struct timezone *tz)"
+    "-1"
+    "sys/time.h"
+    HAVE_GETTIMEOFDAY_TZ)
+
+# TODO
+set(HAVE_IPV6 TRUE)
+
+# ENDIAN
+if (NOT WIN32)
+    test_big_endian(WORDS_BIGENDIAN)
+endif (NOT WIN32)
diff --git a/DefineOptions.cmake b/DefineOptions.cmake
new file mode 100644 (file)
index 0000000..ea8265c
--- /dev/null
@@ -0,0 +1,27 @@
+option(WITH_ZLIB "Build with ZLIB support" ON)
+option(WITH_SSH1 "Build with SSH1 support" OFF)
+option(WITH_SFTP "Build with SFTP support" ON)
+option(WITH_SERVER "Build with SSH server support" ON)
+option(WITH_STATIC_LIB "Build with a static library" OFF)
+option(WITH_DEBUG_CRYPTO "Build with cryto debug output" OFF)
+option(WITH_DEBUG_CALLTRACE "Build with calltrace debug output" ON)
+option(WITH_GCRYPT "Compile against libgcrypt" OFF)
+option(WITH_PCAP "Compile with Pcap generation support" ON)
+option(WITH_INTERNAL_DOC "Compile doxygen internal documentation" OFF)
+option(WITH_TESTING "Build with unit tests" OFF)
+option(WITH_CLIENT_TESTING "Build with client tests; requires a running sshd" OFF)
+option(WITH_BENCHMARKS "Build benchmarks tools" OFF)
+
+if (WITH_ZLIB)
+    set(WITH_LIBZ ON)
+else (WITH_ZLIB)
+    set(WITH_LIBZ OFF)
+endif (WITH_ZLIB)
+
+if(WITH_BENCHMARKS)
+  set(WITH_TESTING ON)
+endif(WITH_BENCHMARKS)
+
+if (WITH_TESTING)
+  set(WITH_STATIC_LIB ON)
+endif (WITH_TESTING)
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..7646883
--- /dev/null
+++ b/README
@@ -0,0 +1,18 @@
+Socket wrapper library
+=======================
+
+This library passes all socket communication over unix domain sockets if the
+environment variable SOCKET_WRAPPER_DIR is set.
+
+It need to be preloaded with LD_PRELOAD.
+
+Environment variables which could be set:
+
+SOCKET_WRAPPER_DIR
+    The directory to place all unix sockets.
+
+SOCKET_WRAPPER_DEFAULT_IFACE
+
+SOCKET_WRAPPER_PCAP_FILE
+    If set then all traffic will be written to the
+    specified pcap file.
diff --git a/cmake/Modules/COPYING-CMAKE-SCRIPTS b/cmake/Modules/COPYING-CMAKE-SCRIPTS
new file mode 100644 (file)
index 0000000..4b41776
--- /dev/null
@@ -0,0 +1,22 @@
+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 copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products 
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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/cmake/Modules/CheckCCompilerFlagSSP.cmake b/cmake/Modules/CheckCCompilerFlagSSP.cmake
new file mode 100644 (file)
index 0000000..2fe4395
--- /dev/null
@@ -0,0 +1,26 @@
+# - Check whether the C compiler supports a given flag in the
+# context of a stack checking compiler option.
+
+# CHECK_C_COMPILER_FLAG_SSP(FLAG VARIABLE)
+#
+#  FLAG - the compiler flag
+#  VARIABLE - variable to store the result
+#
+#  This actually calls check_c_source_compiles.
+#  See help for CheckCSourceCompiles for a listing of variables
+#  that can modify the build.
+
+# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+
+include(CheckCSourceCompiles)
+
+function(CHECK_C_COMPILER_FLAG_SSP _FLAG _RESULT)
+   set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
+   set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
+   check_c_source_compiles("int main(int argc, char **argv) { char buffer[256]; return buffer[argc]=0;}" ${_RESULT})
+   set(CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
+endfunction(CHECK_C_COMPILER_FLAG_SSP)
diff --git a/cmake/Modules/DefineCMakeDefaults.cmake b/cmake/Modules/DefineCMakeDefaults.cmake
new file mode 100644 (file)
index 0000000..72893c3
--- /dev/null
@@ -0,0 +1,27 @@
+# Always include srcdir and builddir in include path
+# This saves typing ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY} in
+# about every subdir
+# since cmake 2.4.0
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+# Put the include dirs which are in the source or build tree
+# before all other include dirs, so the headers in the sources
+# are prefered over the already installed ones
+# since cmake 2.4.1
+set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON)
+
+# Use colored output
+# since cmake 2.4.0
+set(CMAKE_COLOR_MAKEFILE ON)
+
+# Define the generic version of the libraries here
+set(GENERIC_LIB_VERSION "0.1.0")
+set(GENERIC_LIB_SOVERSION "0")
+
+# Set the default build type to release with debug info
+if (NOT CMAKE_BUILD_TYPE)
+  set(CMAKE_BUILD_TYPE RelWithDebInfo
+    CACHE STRING
+      "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
+  )
+endif (NOT CMAKE_BUILD_TYPE)
diff --git a/cmake/Modules/DefineCompilerFlags.cmake b/cmake/Modules/DefineCompilerFlags.cmake
new file mode 100644 (file)
index 0000000..0283b12
--- /dev/null
@@ -0,0 +1,75 @@
+# define system dependent compiler flags
+
+include(CheckCCompilerFlag)
+include(CheckCCompilerFlagSSP)
+
+if (UNIX AND NOT WIN32)
+    #
+    # Define GNUCC compiler flags
+    #
+    if (${CMAKE_C_COMPILER_ID} MATCHES "(GNU|Clang)")
+
+        # add -Wconversion ?
+        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -pedantic -pedantic-errors")
+        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wshadow -Wmissing-prototypes -Wdeclaration-after-statement")
+        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused -Wfloat-equal -Wpointer-arith -Wwrite-strings -Wformat-security")
+        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-format-attribute")
+
+        # with -fPIC
+        check_c_compiler_flag("-fPIC" WITH_FPIC)
+        if (WITH_FPIC)
+            set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
+        endif (WITH_FPIC)
+
+        check_c_compiler_flag_ssp("-fstack-protector" WITH_STACK_PROTECTOR)
+        if (WITH_STACK_PROTECTOR)
+            set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector")
+        endif (WITH_STACK_PROTECTOR)
+
+        string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER)
+        if (NOT CMAKE_BUILD_TYPE_LOWER MATCHES debug)
+            check_c_compiler_flag("-D_FORTIFY_SOURCE=2" WITH_FORTIFY_SOURCE)
+            if (WITH_FORTIFY_SOURCE)
+                set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2")
+            endif (WITH_FORTIFY_SOURCE)
+        endif()
+    endif (${CMAKE_C_COMPILER_ID} MATCHES "(GNU|Clang)")
+
+    #
+    # Check for large filesystem support
+    #
+    if (CMAKE_SIZEOF_VOID_P MATCHES "8")
+        # with large file support
+        execute_process(
+            COMMAND
+                getconf LFS64_CFLAGS
+            OUTPUT_VARIABLE
+                _lfs_CFLAGS
+            ERROR_QUIET
+            OUTPUT_STRIP_TRAILING_WHITESPACE
+        )
+    else (CMAKE_SIZEOF_VOID_P MATCHES "8")
+        # with large file support
+        execute_process(
+            COMMAND
+                getconf LFS_CFLAGS
+            OUTPUT_VARIABLE
+                _lfs_CFLAGS
+            ERROR_QUIET
+            OUTPUT_STRIP_TRAILING_WHITESPACE
+        )
+    endif (CMAKE_SIZEOF_VOID_P MATCHES "8")
+    if (_lfs_CFLAGS)
+        string(REGEX REPLACE "[\r\n]" " " "${_lfs_CFLAGS}" "${${_lfs_CFLAGS}}")
+        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_lfs_CFLAGS}")
+    endif (_lfs_CFLAGS)
+
+endif (UNIX AND NOT WIN32)
+
+if (MSVC)
+    # Use secure functions by defaualt and suppress warnings about
+    #"deprecated" functions
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1")
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1")
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1")
+endif (MSVC)
diff --git a/cmake/Modules/DefineInstallationPaths.cmake b/cmake/Modules/DefineInstallationPaths.cmake
new file mode 100644 (file)
index 0000000..d857871
--- /dev/null
@@ -0,0 +1,104 @@
+if (WIN32)
+  # Same same
+  set(BIN_INSTALL_DIR "bin" CACHE PATH "-")
+  set(SBIN_INSTALL_DIR "." CACHE PATH "-")
+  set(LIB_INSTALL_DIR "lib" CACHE PATH "-")
+  set(INCLUDE_INSTALL_DIR "include" CACHE PATH "-")
+  set(PLUGIN_INSTALL_DIR "plugins" CACHE PATH "-")
+  set(HTML_INSTALL_DIR "doc/HTML" CACHE PATH "-")
+  set(ICON_INSTALL_DIR "." CACHE PATH "-")
+  set(SOUND_INSTALL_DIR "." CACHE PATH "-")
+  set(LOCALE_INSTALL_DIR "lang" CACHE PATH "-")
+elseif (UNIX OR OS2)
+  IF (NOT APPLICATION_NAME)
+    MESSAGE(STATUS "${PROJECT_NAME} is used as APPLICATION_NAME")
+    SET(APPLICATION_NAME ${PROJECT_NAME})
+  ENDIF (NOT APPLICATION_NAME)
+
+  # Suffix for Linux
+  SET(LIB_SUFFIX
+    CACHE STRING "Define suffix of directory name (32/64)"
+  )
+
+  SET(EXEC_INSTALL_PREFIX
+    "${CMAKE_INSTALL_PREFIX}"
+    CACHE PATH  "Base directory for executables and libraries"
+  )
+  SET(SHARE_INSTALL_PREFIX
+    "${CMAKE_INSTALL_PREFIX}/share"
+    CACHE PATH "Base directory for files which go to share/"
+  )
+  SET(DATA_INSTALL_PREFIX
+    "${SHARE_INSTALL_PREFIX}/${APPLICATION_NAME}"
+    CACHE PATH "The parent directory where applications can install their data")
+
+  # The following are directories where stuff will be installed to
+  SET(BIN_INSTALL_DIR
+    "${EXEC_INSTALL_PREFIX}/bin"
+    CACHE PATH "The ${APPLICATION_NAME} binary install dir (default prefix/bin)"
+  )
+  SET(SBIN_INSTALL_DIR
+    "${EXEC_INSTALL_PREFIX}/sbin"
+    CACHE PATH "The ${APPLICATION_NAME} sbin install dir (default prefix/sbin)"
+  )
+  SET(LIB_INSTALL_DIR
+    "${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}"
+    CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/lib)"
+  )
+  SET(LIBEXEC_INSTALL_DIR
+    "${EXEC_INSTALL_PREFIX}/libexec"
+    CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/libexec)"
+  )
+  SET(PLUGIN_INSTALL_DIR
+    "${LIB_INSTALL_DIR}/${APPLICATION_NAME}"
+    CACHE PATH "The subdirectory relative to the install prefix where plugins will be installed (default is prefix/lib/${APPLICATION_NAME})"
+  )
+  SET(INCLUDE_INSTALL_DIR
+    "${CMAKE_INSTALL_PREFIX}/include"
+    CACHE PATH "The subdirectory to the header prefix (default prefix/include)"
+  )
+
+  SET(DATA_INSTALL_DIR
+    "${DATA_INSTALL_PREFIX}"
+    CACHE PATH "The parent directory where applications can install their data (default prefix/share/${APPLICATION_NAME})"
+  )
+  SET(HTML_INSTALL_DIR
+    "${DATA_INSTALL_PREFIX}/doc/HTML"
+    CACHE PATH "The HTML install dir for documentation (default data/doc/html)"
+  )
+  SET(ICON_INSTALL_DIR
+    "${DATA_INSTALL_PREFIX}/icons"
+    CACHE PATH "The icon install dir (default data/icons/)"
+  )
+  SET(SOUND_INSTALL_DIR
+    "${DATA_INSTALL_PREFIX}/sounds"
+    CACHE PATH "The install dir for sound files (default data/sounds)"
+  )
+
+  SET(LOCALE_INSTALL_DIR
+    "${SHARE_INSTALL_PREFIX}/locale"
+    CACHE PATH "The install dir for translations (default prefix/share/locale)"
+  )
+
+  SET(XDG_APPS_DIR
+    "${SHARE_INSTALL_PREFIX}/applications/"
+    CACHE PATH "The XDG apps dir"
+  )
+  SET(XDG_DIRECTORY_DIR
+    "${SHARE_INSTALL_PREFIX}/desktop-directories"
+    CACHE PATH "The XDG directory"
+  )
+
+  SET(SYSCONF_INSTALL_DIR
+    "${EXEC_INSTALL_PREFIX}/etc"
+    CACHE PATH "The ${APPLICATION_NAME} sysconfig install dir (default prefix/etc)"
+  )
+  SET(MAN_INSTALL_DIR
+    "${SHARE_INSTALL_PREFIX}/man"
+    CACHE PATH "The ${APPLICATION_NAME} man install dir (default prefix/man)"
+  )
+  SET(INFO_INSTALL_DIR
+    "${SHARE_INSTALL_PREFIX}/info"
+    CACHE PATH "The ${APPLICATION_NAME} info install dir (default prefix/info)"
+  )
+endif ()
diff --git a/cmake/Modules/DefinePlatformDefaults.cmake b/cmake/Modules/DefinePlatformDefaults.cmake
new file mode 100644 (file)
index 0000000..502d936
--- /dev/null
@@ -0,0 +1,28 @@
+# Set system vars
+
+if (CMAKE_SYSTEM_NAME MATCHES "Linux")
+    set(LINUX TRUE)
+endif(CMAKE_SYSTEM_NAME MATCHES "Linux")
+
+if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+    set(FREEBSD TRUE)
+    set(BSD TRUE)
+endif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+
+if (CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
+    set(OPENBSD TRUE)
+    set(BSD TRUE)
+endif (CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
+
+if (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
+    set(NETBSD TRUE)
+    set(BSD TRUE)
+endif (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
+
+if (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
+    set(SOLARIS TRUE)
+endif (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
+
+if (CMAKE_SYSTEM_NAME MATCHES "OS2")
+    set(OS2 TRUE)
+endif (CMAKE_SYSTEM_NAME MATCHES "OS2")
diff --git a/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake b/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake
new file mode 100644 (file)
index 0000000..a2e9480
--- /dev/null
@@ -0,0 +1,17 @@
+# - MACRO_ENSURE_OUT_OF_SOURCE_BUILD(<errorMessage>)
+# MACRO_ENSURE_OUT_OF_SOURCE_BUILD(<errorMessage>)
+
+# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+macro (MACRO_ENSURE_OUT_OF_SOURCE_BUILD _errorMessage)
+
+   string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" _insource)
+   if (_insource)
+     message(SEND_ERROR "${_errorMessage}")
+     message(FATAL_ERROR "Remove the file CMakeCache.txt in ${CMAKE_SOURCE_DIR} first.")
+   endif (_insource)
+
+endmacro (MACRO_ENSURE_OUT_OF_SOURCE_BUILD)
diff --git a/config.h.cmake b/config.h.cmake
new file mode 100644 (file)
index 0000000..6c9633d
--- /dev/null
@@ -0,0 +1,58 @@
+/* Name of package */
+#cmakedefine PACKAGE "${APPLICATION_NAME}"
+
+/* Version number of package */
+#cmakedefine VERSION "${APPLICATION_VERSION}"
+
+#cmakedefine LOCALEDIR "${LOCALE_INSTALL_DIR}"
+#cmakedefine DATADIR "${DATADIR}"
+#cmakedefine LIBDIR "${LIBDIR}"
+#cmakedefine PLUGINDIR "${PLUGINDIR}"
+#cmakedefine SYSCONFDIR "${SYSCONFDIR}"
+#cmakedefine BINARYDIR "${BINARYDIR}"
+#cmakedefine SOURCEDIR "${SOURCEDIR}"
+
+/************************** HEADER FILES *************************/
+
+#cmakedefine HAVE_SYS_FILIO_H 1
+
+
+/*************************** FUNCTIONS ***************************/
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#cmakedefine HAVE_GETADDRINFO 1
+
+/*************************** LIBRARIES ***************************/
+
+#cmakedefine HAVE_GETTIMEOFDAY_TZ 1
+
+/**************************** OPTIONS ****************************/
+
+/* Define to 1 if you want to enable ZLIB */
+#cmakedefine WITH_ZLIB 1
+
+/* Define to 1 if you want to enable SFTP */
+#cmakedefine WITH_SFTP 1
+
+/* Define to 1 if you want to enable SSH1 */
+#cmakedefine WITH_SSH1 1
+
+/* Define to 1 if you want to enable server support */
+#cmakedefine WITH_SERVER 1
+
+/* Define to 1 if you want to enable debug output for crypto functions */
+#cmakedefine DEBUG_CRYPTO 1
+
+/* Define to 1 if you want to enable pcap output support (experimental) */
+#cmakedefine WITH_PCAP 1
+
+/* Define to 1 if you want to enable calltrace debug output */
+#cmakedefine DEBUG_CALLTRACE 1
+
+#cmakedefine HAVE_IPV6 1
+
+/*************************** ENDIAN *****************************/
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#cmakedefine WORDS_BIGENDIAN 1
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5c4aa29
--- /dev/null
@@ -0,0 +1,4 @@
+project(libsocket_wrapper C)
+
+include_directories(${CMAKE_BINARY_DIR})
+add_library(socket_wrapper SHARED socket_wrapper.c)
diff --git a/src/py_socket_wrapper.c b/src/py_socket_wrapper.c
new file mode 100644 (file)
index 0000000..f5742d3
--- /dev/null
@@ -0,0 +1,883 @@
+/*
+ * Copyright (C) Amitay Isaacs 2011
+ *
+ * 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. Neither the name of the author 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 AUTHOR 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 AUTHOR 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.
+ *
+ */
+
+/*
+   Python interface to socket wrapper library.
+
+   Passes all socket communication over unix domain sockets if the environment
+   variable SOCKET_WRAPPER_DIR is set.
+*/
+
+#include <Python.h>
+#include <pytalloc.h>
+#include "replace/replace.h"
+#include "system/network.h"
+#include "socket_wrapper.h"
+
+/* There's no Py_ssize_t in 2.4, apparently */
+#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 5
+typedef int Py_ssize_t;
+typedef inquiry lenfunc;
+typedef intargfunc ssizeargfunc;
+#endif
+
+#ifndef Py_RETURN_NONE
+#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
+#endif
+
+#ifndef Py_TYPE /* Py_TYPE is only available on Python > 2.6 */
+#define Py_TYPE(ob)            (((PyObject*)(ob))->ob_type)
+#endif
+
+#ifndef PY_CHECK_TYPE
+#define PY_CHECK_TYPE(type, var, fail) \
+       if (!PyObject_TypeCheck(var, type)) {\
+               PyErr_Format(PyExc_TypeError, __location__ ": Expected type '%s' for '%s' of type '%s'", (type)->tp_name, #var, Py_TYPE(var)->tp_name); \
+               fail; \
+       }
+#endif
+
+staticforward PyTypeObject PySocket;
+
+static PyObject *py_socket_error;
+
+void initsocket_wrapper(void);
+
+static PyObject *py_socket_addr_to_tuple(struct sockaddr *addr, socklen_t len)
+{
+       char host[256];
+       char service[8];
+       int status;
+       PyObject *pyaddr;
+
+       status = getnameinfo(addr, len, host, 255, service, 7, NI_NUMERICHOST|NI_NUMERICSERV);
+       if (status < 0) {
+               PyErr_SetString(py_socket_error, gai_strerror(status));
+               return NULL;
+       }
+
+       pyaddr = PyTuple_New(2);
+       if (pyaddr == NULL) {
+               return PyErr_NoMemory();
+       }
+
+       PyTuple_SetItem(pyaddr, 0, PyString_FromString(host));
+       PyTuple_SetItem(pyaddr, 1, PyInt_FromLong(atoi(service)));
+
+       return pyaddr;
+}
+
+static bool py_socket_tuple_to_addr(PyObject *pyaddr, struct sockaddr *addr, socklen_t *len)
+{
+       const char *host;
+       char *service;
+       in_port_t port;
+       struct addrinfo *ainfo;
+       int status;
+
+       if (!PyTuple_Check(pyaddr)) {
+               PyErr_SetString(PyExc_TypeError, "Expected a tuple");
+               return false;
+       }
+
+       if (!PyArg_ParseTuple(pyaddr, "sH", &host, &port)) {
+               return false;
+       }
+
+       service = talloc_asprintf(NULL, "%d", port);
+       if (service == NULL) {
+               PyErr_NoMemory();
+               return false;
+       }
+
+       status = getaddrinfo(host, service, NULL, &ainfo);
+       if (status < 0) {
+               talloc_free(service);
+               PyErr_SetString(py_socket_error, gai_strerror(status));
+               return false;
+       }
+
+       talloc_free(service);
+
+       memcpy(addr, ainfo->ai_addr, sizeof(struct sockaddr));
+       *len = ainfo->ai_addrlen;
+
+       freeaddrinfo(ainfo);
+       return true;
+}
+
+
+static PyObject *py_socket_accept(pytalloc_Object *self, PyObject *args)
+{
+       int *sock, *new_sock;
+       struct sockaddr addr;
+       socklen_t addrlen;
+       PyObject *pysocket;
+       PyObject *pyaddr;
+       PyObject *pyret;
+
+       sock = pytalloc_get_ptr(self);
+
+       new_sock = talloc_zero(NULL, int);
+       if (new_sock == NULL) {
+               return PyErr_NoMemory();
+       }
+
+       *new_sock = swrap_accept(*sock, &addr, &addrlen);
+       if (*new_sock < 0) {
+               return PyErr_SetFromErrno(py_socket_error);
+       }
+
+       if ((pysocket = pytalloc_steal(&PySocket, new_sock)) == NULL) {
+               return PyErr_NoMemory();
+       }
+
+       pyret = PyTuple_New(2);
+       if (pyret == NULL) {
+               Py_DECREF(pysocket);
+               return PyErr_NoMemory();
+       }
+
+       pyaddr = py_socket_addr_to_tuple(&addr, addrlen);
+       if (pyaddr == NULL) {
+               Py_DECREF(pysocket);
+               Py_DECREF(pysocket);
+               return NULL;
+       }
+
+       PyTuple_SetItem(pyret, 0, pysocket);
+       PyTuple_SetItem(pyret, 1, pyaddr);
+       return pyret;
+}
+
+static PyObject *py_socket_bind(pytalloc_Object *self, PyObject *args)
+{
+       PyObject *pyaddr;
+       int *sock;
+       int status;
+       struct sockaddr addr;
+       socklen_t addrlen;
+
+       if (!PyArg_ParseTuple(args, "O:bind", &pyaddr)) {
+               return NULL;
+       }
+
+       if (!py_socket_tuple_to_addr(pyaddr, &addr, &addrlen)) {
+               return NULL;
+       }
+
+       sock = pytalloc_get_ptr(self);
+
+       status = swrap_bind(*sock, &addr, addrlen);
+       if (status < 0) {
+               PyErr_SetString(py_socket_error, "Unable to bind");
+               return NULL;
+       }
+
+       Py_RETURN_NONE;
+}
+
+static PyObject *py_socket_close(pytalloc_Object *self, PyObject *args)
+{
+       int *sock;
+       int status;
+
+       sock = pytalloc_get_ptr(self);
+
+       status = swrap_close(*sock);
+       if (status < 0) {
+               return PyErr_SetFromErrno(py_socket_error);
+       }
+
+       Py_RETURN_NONE;
+}
+
+static PyObject *py_socket_connect(pytalloc_Object *self, PyObject *args)
+{
+       int *sock;
+       PyObject *pyaddr;
+       struct sockaddr addr;
+       socklen_t addrlen;
+       int status;
+
+       if (!PyArg_ParseTuple(args, "O:connect", &pyaddr)) {
+               return NULL;
+       }
+
+       if (!py_socket_tuple_to_addr(pyaddr, &addr, &addrlen)) {
+               return NULL;
+       }
+
+       sock = pytalloc_get_ptr(self);
+
+       status = swrap_connect(*sock, &addr, addrlen);
+       if (status < 0) {
+               PyErr_SetFromErrno(py_socket_error);
+               return NULL;
+       }
+
+       Py_RETURN_NONE;
+}
+
+static PyObject *py_socket_connect_ex(pytalloc_Object *self, PyObject *args)
+{
+       int *sock;
+       PyObject *pyaddr;
+       struct sockaddr addr;
+       socklen_t addrlen;
+       int status;
+
+       if (!PyArg_ParseTuple(args, "O:connect", &pyaddr)) {
+               return NULL;
+       }
+
+       if (!py_socket_tuple_to_addr(pyaddr, &addr, &addrlen)) {
+               return NULL;
+       }
+
+       sock = pytalloc_get_ptr(self);
+
+       status = swrap_connect(*sock, &addr, addrlen);
+       if (status < 0) {
+               return Py_BuildValue("%d", errno);
+       }
+
+       return Py_BuildValue("%d", 0);
+}
+
+static PyObject *py_socket_dup(pytalloc_Object *self, PyObject *args)
+{
+       int *sock, *new_sock;
+       PyObject *pysocket;
+
+       sock = pytalloc_get_ptr(self);
+
+       new_sock = talloc_zero(NULL, int);
+       if (new_sock == NULL) {
+               return PyErr_NoMemory();
+       }
+
+       *new_sock = swrap_dup(*sock);
+       if (*new_sock < 0) {
+               return PyErr_SetFromErrno(py_socket_error);
+       }
+
+       pysocket = pytalloc_steal(&PySocket, new_sock);
+       if (pysocket == NULL) {
+               return PyErr_NoMemory();
+       }
+
+       return pysocket;
+}
+
+static PyObject *py_socket_dup2(pytalloc_Object *self, PyObject *args)
+{
+       int *sock, *new_sock;
+       PyObject *pysocket;
+       int status;
+
+       if (!PyArg_ParseTuple(args, "O", &pysocket)) {
+               return NULL;
+       }
+
+       PY_CHECK_TYPE(&PySocket, pysocket, return NULL);
+
+       sock = pytalloc_get_ptr(self);
+       new_sock = pytalloc_get_ptr(pysocket);
+
+       status = swrap_dup2(*sock, *new_sock);
+       if (status < 0) {
+               return PyErr_SetFromErrno(py_socket_error);
+       }
+
+       Py_RETURN_NONE;
+}
+
+static PyObject *py_socket_fileno(pytalloc_Object *self, PyObject *args)
+{
+       PyErr_SetString(py_socket_error, "Not Supported");
+       return NULL;
+}
+
+static PyObject *py_socket_getpeername(pytalloc_Object *self, PyObject *args)
+{
+       int *sock;
+       struct sockaddr addr;
+       socklen_t addrlen;
+       int status;
+       PyObject *pyaddr;
+
+       sock = pytalloc_get_ptr(self);
+
+       status = swrap_getpeername(*sock, &addr, &addrlen);
+       if (status < 0) {
+               return PyErr_SetFromErrno(py_socket_error);
+       }
+
+       pyaddr = py_socket_addr_to_tuple(&addr, addrlen);
+
+       return pyaddr;
+}
+
+static PyObject *py_socket_getsockname(pytalloc_Object *self, PyObject *args)
+{
+       int *sock;
+       struct sockaddr addr;
+       socklen_t addrlen;
+       int status;
+       PyObject *pyaddr;
+
+       sock = pytalloc_get_ptr(self);
+
+       status = swrap_getsockname(*sock, &addr, &addrlen);
+       if (status < 0) {
+               return PyErr_SetFromErrno(py_socket_error);
+       }
+
+       pyaddr = py_socket_addr_to_tuple(&addr, addrlen);
+
+       return pyaddr;
+}
+
+static PyObject *py_socket_getsockopt(pytalloc_Object *self, PyObject *args)
+{
+       int level, optname;
+       int *sock;
+       socklen_t optlen = 0, newlen;
+       int optval;
+       bool is_integer = false;
+       char *buffer;
+       PyObject *pyret;
+       int status;
+
+       if (!PyArg_ParseTuple(args, "ii|i:getsockopt", &level, &optname, &optlen)) {
+               return NULL;
+       }
+
+       if (optlen == 0) {
+               optlen = sizeof(int);
+               is_integer = true;
+       }
+
+       buffer = talloc_zero_array(NULL, char, optlen);
+       if (buffer == NULL) {
+               return PyErr_NoMemory();
+       }
+
+       sock = pytalloc_get_ptr(self);
+
+       status = swrap_getsockopt(*sock, level, optname, (void *)buffer, &newlen);
+       if (status < 0) {
+               talloc_free(buffer);
+               return PyErr_SetFromErrno(py_socket_error);
+       }
+
+       if (is_integer) {
+               optval = *(int *)buffer;
+               pyret = PyInt_FromLong(optval);
+       } else {
+               pyret = PyString_FromStringAndSize(buffer, optlen);
+       }
+
+       talloc_free(buffer);
+
+       return pyret;
+}
+
+static PyObject *py_socket_gettimeout(pytalloc_Object *self, PyObject *args)
+{
+       PyErr_SetString(py_socket_error, "Not Supported");
+       return NULL;
+}
+
+static PyObject *py_socket_listen(pytalloc_Object *self, PyObject *args)
+{
+       int backlog;
+       int *sock;
+       int status;
+
+       if (!PyArg_ParseTuple(args, "i:listen", &backlog)) {
+               return NULL;
+       }
+
+       sock = pytalloc_get_ptr(self);
+
+       status = swrap_listen(*sock, backlog);
+       if (status < 0) {
+               return PyErr_SetFromErrno(py_socket_error);
+       }
+
+       Py_RETURN_NONE;
+}
+
+static PyObject *py_socket_makefile(pytalloc_Object *self, PyObject *args)
+{
+       PyErr_SetString(py_socket_error, "Not Supported");
+       return NULL;
+}
+
+static PyObject *py_socket_read(pytalloc_Object *self, PyObject *args)
+{
+       int bufsize, len;
+       int *sock;
+       char *buffer;
+       PyObject *pyret;
+
+       if (!PyArg_ParseTuple(args, "i:read", &bufsize)) {
+               return NULL;
+       }
+
+       buffer = talloc_zero_array(NULL, char, bufsize);
+       if (buffer == NULL) {
+               return PyErr_NoMemory();
+       }
+
+       sock = pytalloc_get_ptr(self);
+
+       len = swrap_read(*sock, buffer, bufsize);
+       if (len < 0) {
+               return PyErr_SetFromErrno(py_socket_error);
+       }
+
+       pyret = PyString_FromStringAndSize(buffer, len);
+
+       talloc_free(buffer);
+
+       return pyret;
+}
+
+static PyObject *py_socket_recv(pytalloc_Object *self, PyObject *args)
+{
+       int bufsize, flags, len;
+       int *sock;
+       char *buffer;
+       PyObject *pyret;
+
+       if (!PyArg_ParseTuple(args, "ii:recv", &bufsize, &flags)) {
+               return NULL;
+       }
+
+       buffer = talloc_zero_array(NULL, char, bufsize);
+       if (buffer == NULL) {
+               return PyErr_NoMemory();
+       }
+
+       sock = pytalloc_get_ptr(self);
+
+       len = swrap_recv(*sock, buffer, bufsize, flags);
+       if (len < 0) {
+               return PyErr_SetFromErrno(py_socket_error);
+       }
+
+       pyret = PyString_FromStringAndSize(buffer, len);
+
+       talloc_free(buffer);
+
+       return pyret;
+}
+
+static PyObject *py_socket_recvfrom(pytalloc_Object *self, PyObject *args)
+{
+       int bufsize, flags, len;
+       int *sock;
+       char *buffer;
+       struct sockaddr from;
+       socklen_t fromlen;
+       PyObject *pybuf, *pyaddr, *pyret;
+
+       if (!PyArg_ParseTuple(args, "ii:recvfrom", &bufsize, &flags)) {
+               return NULL;
+       }
+
+       buffer = talloc_zero_array(NULL, char, bufsize);
+       if (buffer == NULL) {
+               return PyErr_NoMemory();
+       }
+
+       sock = pytalloc_get_ptr(self);
+
+       fromlen = sizeof(struct sockaddr);
+
+       len = swrap_recvfrom(*sock, buffer, bufsize, flags, &from, &fromlen);
+       if (len < 0) {
+               talloc_free(buffer);
+               return PyErr_SetFromErrno(py_socket_error);
+       }
+
+       pybuf = PyString_FromStringAndSize(buffer, len);
+       if (pybuf == NULL) {
+               talloc_free(buffer);
+               return PyErr_NoMemory();
+       }
+
+       talloc_free(buffer);
+
+       pyaddr = py_socket_addr_to_tuple(&from, fromlen);
+       if (pyaddr == NULL) {
+               Py_DECREF(pybuf);
+               return NULL;
+       }
+
+       pyret = PyTuple_New(2);
+       if (pyret == NULL) {
+               Py_DECREF(pybuf);
+               Py_DECREF(pyaddr);
+               return PyErr_NoMemory();
+       }
+
+       PyTuple_SetItem(pyret, 0, pybuf);
+       PyTuple_SetItem(pyret, 1, pyaddr);
+
+       return pyret;
+}
+
+static PyObject *py_socket_send(pytalloc_Object *self, PyObject *args)
+{
+       char *buffer;
+       int len, flags;
+       int *sock;
+       int status;
+
+       if (!PyArg_ParseTuple(args, "s#i:sendto", &buffer, &len, &flags)) {
+               return NULL;
+       }
+
+       sock = pytalloc_get_ptr(self);
+
+       status = swrap_send(*sock, buffer, len, flags);
+       if (status < 0) {
+               PyErr_SetFromErrno(py_socket_error);
+               return NULL;
+       }
+
+       Py_RETURN_NONE;
+}
+
+static PyObject *py_socket_sendall(pytalloc_Object *self, PyObject *args)
+{
+       char *buffer;
+       int len, flags;
+       int *sock;
+       int status;
+
+       if (!PyArg_ParseTuple(args, "s#i:sendall", &buffer, &len, &flags)) {
+               return NULL;
+       }
+
+       sock = pytalloc_get_ptr(self);
+
+       status = swrap_send(*sock, buffer, len, flags);
+       if (status < 0) {
+               PyErr_SetFromErrno(py_socket_error);
+               return NULL;
+       }
+
+       Py_RETURN_NONE;
+}
+
+static PyObject *py_socket_sendto(pytalloc_Object *self, PyObject *args)
+{
+       PyObject *pyaddr;
+       char *buffer;
+       int len, flags;
+       int *sock;
+       struct sockaddr addr;
+       socklen_t addrlen;
+       int status;
+
+       if (!PyArg_ParseTuple(args, "s#iO:sendto", &buffer, &len, &flags, &pyaddr)) {
+               return NULL;
+       }
+
+       if (!py_socket_tuple_to_addr(pyaddr, &addr, &addrlen)) {
+               return NULL;
+       }
+
+       sock = pytalloc_get_ptr(self);
+
+       status = swrap_sendto(*sock, buffer, len, flags, &addr, addrlen);
+       if (status < 0) {
+               PyErr_SetFromErrno(py_socket_error);
+               return NULL;
+       }
+
+       Py_RETURN_NONE;
+}
+
+static PyObject *py_socket_setblocking(pytalloc_Object *self, PyObject *args)
+{
+       PyErr_SetString(py_socket_error, "Not Supported");
+       return NULL;
+}
+
+static PyObject *py_socket_setsockopt(pytalloc_Object *self, PyObject *args)
+{
+       int level, optname;
+       int *sock;
+       PyObject *pyval;
+       int optval;
+       Py_ssize_t optlen;
+       char *buffer;
+       int status;
+
+       if (!PyArg_ParseTuple(args, "iiO:getsockopt", &level, &optname, &pyval)) {
+               return NULL;
+       }
+
+       if (PyInt_Check(pyval)) {
+               optval = PyInt_AsLong(pyval);
+               buffer = (char *)&optval;
+               optlen = sizeof(int);
+       } else {
+               PyString_AsStringAndSize(pyval, &buffer, &optlen);
+       }
+
+       sock = pytalloc_get_ptr(self);
+
+       status = swrap_setsockopt(*sock, level, optname, (void *)buffer, optlen);
+       if (status < 0) {
+               return PyErr_SetFromErrno(py_socket_error);
+       }
+
+       Py_RETURN_NONE;
+}
+
+static PyObject *py_socket_settimeout(pytalloc_Object *self, PyObject *args)
+{
+       PyErr_SetString(py_socket_error, "Not Supported");
+       return NULL;
+}
+
+static PyObject *py_socket_shutdown(pytalloc_Object *self, PyObject *args)
+{
+       PyErr_SetString(py_socket_error, "Not Supported");
+       return NULL;
+}
+
+static PyObject *py_socket_write(pytalloc_Object *self, PyObject *args)
+{
+       char *buffer;
+       int len;
+       int *sock;
+       int status;
+
+       if (!PyArg_ParseTuple(args, "s#:write", &buffer, &len)) {
+               return NULL;
+       }
+
+       sock = pytalloc_get_ptr(self);
+
+       status = swrap_send(*sock, buffer, len, 0);
+       if (status < 0) {
+               PyErr_SetFromErrno(py_socket_error);
+               return NULL;
+       }
+
+       Py_RETURN_NONE;
+}
+
+
+static PyMethodDef py_socket_methods[] = {
+       { "accept", (PyCFunction)py_socket_accept, METH_NOARGS,
+               "accept() -> (socket object, address info)\n\n \
+               Wait for an incoming connection." },
+       { "bind", (PyCFunction)py_socket_bind, METH_VARARGS,
+               "bind(address)\n\n \
+               Bind the socket to a local address." },
+       { "close", (PyCFunction)py_socket_close, METH_NOARGS,
+               "close()\n\n \
+               Close the socket." },
+       { "connect", (PyCFunction)py_socket_connect, METH_VARARGS,
+               "connect(address)\n\n \
+               Connect the socket to a remote address." },
+       { "connect_ex", (PyCFunction)py_socket_connect_ex, METH_VARARGS,
+               "connect_ex(address)\n\n \
+               Connect the socket to a remote address." },
+       { "dup", (PyCFunction)py_socket_dup, METH_VARARGS,
+               "dup() -> socket object\n\n \
+               Return a new socket object connected to the same system resource." },
+       { "dup2", (PyCFunction)py_socket_dup2, METH_VARARGS,
+               "dup2(socket object) -> socket object\n\n \
+               Return a new socket object connected to teh same system resource." },
+       { "fileno", (PyCFunction)py_socket_fileno, METH_NOARGS,
+               "fileno() -> file descriptor\n\n \
+               Return socket's file descriptor." },
+       { "getpeername", (PyCFunction)py_socket_getpeername, METH_NOARGS,
+               "getpeername() -> address info\n\n \
+               Return the address of the remote endpoint." },
+       { "getsockname", (PyCFunction)py_socket_getsockname, METH_NOARGS,
+               "getsockname() -> address info\n\n \
+               Return the address of the local endpoing." },
+       { "getsockopt", (PyCFunction)py_socket_getsockopt, METH_VARARGS,
+               "getsockopt(level, option[, buffersize]) -> value\n\n \
+               Get a socket option." },
+       { "gettimeout", (PyCFunction)py_socket_gettimeout, METH_NOARGS,
+               "gettimeout() -> value\n\n \
+               Return the timeout in seconds associated with socket operations." },
+       { "listen", (PyCFunction)py_socket_listen, METH_VARARGS,
+               "listen(backlog)\n\n \
+               Enable a server to accept connections." },
+       { "makefile", (PyCFunction)py_socket_makefile, METH_NOARGS,
+               "makefile() -> file object\n\n \
+               Return a file object associated with the socket." },
+       { "read", (PyCFunction)py_socket_read, METH_VARARGS,
+               "read(buflen) -> data\n\n \
+               Receive data." },
+       { "recv", (PyCFunction)py_socket_recv, METH_VARARGS,
+               "recv(buflen, flags) -> data\n\n \
+               Receive data." },
+       { "recvfrom", (PyCFunction)py_socket_recvfrom, METH_VARARGS,
+               "recvfrom(buflen, flags) -> (data, sender address)\n\n \
+               Receive data and sender's address." },
+       { "send", (PyCFunction)py_socket_send, METH_VARARGS,
+               "send(data, flags)\n\n \
+               Send data." },
+       { "sendall", (PyCFunction)py_socket_sendall, METH_VARARGS,
+               "sendall(data, flags)\n\n \
+               Send data." },
+       { "sendto", (PyCFunction)py_socket_sendto, METH_VARARGS,
+               "sendto(data, flags, addr)\n\n \
+               Send data to a given address." },
+       { "setblocking", (PyCFunction)py_socket_setblocking, METH_VARARGS,
+               "setblocking(flag)\n\n \
+               Set blocking or non-blocking mode of the socket." },
+       { "setsockopt", (PyCFunction)py_socket_setsockopt, METH_VARARGS,
+               "setsockopt(level, option, value)\n\n \
+               Set a socket option." },
+       { "settimeout", (PyCFunction)py_socket_settimeout, METH_VARARGS,
+               "settimeout(value)\n\n \
+               Set a timeout on socket blocking operations." },
+       { "shutdown", (PyCFunction)py_socket_shutdown, METH_VARARGS,
+               "shutdown(how)\n\n \
+               Shut down one or both halves of the connection." },
+       { "write", (PyCFunction)py_socket_write, METH_VARARGS,
+               "write(data)\n\n \
+               Send data." },
+       { NULL },
+};
+
+
+static PyObject *py_socket_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+       int family, sock_type, protocol;
+       int *sock;
+       PyObject *pysocket;
+
+       if (!PyArg_ParseTuple(args, "iii:socket", &family, &sock_type, &protocol)) {
+               return NULL;
+       }
+
+       sock = talloc_zero(NULL, int);
+       if (sock == NULL) {
+               return PyErr_NoMemory();
+       }
+
+       *sock = swrap_socket(family, sock_type, protocol);
+       if (*sock < 0) {
+               return PyErr_SetFromErrno(py_socket_error);
+       }
+
+       if ((pysocket = pytalloc_steal(type, sock)) == NULL) {
+               return PyErr_NoMemory();
+       }
+
+       return pysocket;
+}
+
+
+static PyTypeObject PySocket = {
+       .tp_name = "socket_wrapper.socket",
+       .tp_basicsize = sizeof(pytalloc_Object),
+       .tp_flags = Py_TPFLAGS_DEFAULT,
+       .tp_methods = py_socket_methods,
+       .tp_new = py_socket_new,
+       .tp_doc = "socket(family, type, proto) -> socket object\n\n Open a socket of the give type.",
+};
+
+static PyObject *py_socket_wrapper_dir(PyObject *self)
+{
+       const char *dir;
+
+       dir = socket_wrapper_dir();
+
+       return PyString_FromString(dir);
+}
+
+static PyObject *py_socket_wrapper_default_interface(PyObject *self)
+{
+       unsigned int id;
+
+       id = socket_wrapper_default_iface();
+
+       return PyInt_FromLong(id);
+}
+
+
+static PyMethodDef py_socket_wrapper_methods[] = {
+       { "dir", (PyCFunction)py_socket_wrapper_dir, METH_NOARGS,
+               "dir() -> path\n\n \
+               Return socket_wrapper directory." },
+       { "default_iface", (PyCFunction)py_socket_wrapper_default_interface, METH_NOARGS,
+               "default_iface() -> id\n\n \
+               Return default interface id." },
+       { NULL },
+};
+
+void initsocket_wrapper(void)
+{
+       PyObject *m;
+       char exception_name[] = "socket_wrapper.error";
+
+       PyTypeObject *talloc_type = pytalloc_GetObjectType();
+       if (talloc_type == NULL) {
+               return;
+       }
+
+       PySocket.tp_base = talloc_type;
+       if (PyType_Ready(&PySocket) < 0) {
+               return;
+       }
+
+       m = Py_InitModule3("socket_wrapper", py_socket_wrapper_methods, "Socket wrapper");
+       if (m == NULL) {
+               return;
+       }
+
+       py_socket_error = PyErr_NewException(exception_name, NULL, NULL);
+       Py_INCREF(py_socket_error);
+       PyModule_AddObject(m, "error", py_socket_error);
+
+       Py_INCREF(&PySocket);
+       PyModule_AddObject(m, "socket", (PyObject *)&PySocket);
+}
diff --git a/src/socket.py b/src/socket.py
new file mode 100644 (file)
index 0000000..ccbb820
--- /dev/null
@@ -0,0 +1,50 @@
+# Wrapper for socket wrapper (based on python socket wrapper)
+# Copyright (C) Amitay Isaacs 2011
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import _socket
+from _socket import *
+
+from samba.socket_wrapper import socket
+
+
+def getfqdn(name=''):
+    """Get fully qualified domain name from name.
+
+    An empty argument is interpreted as meaning the local host.
+
+    First the hostname returned by gethostbyaddr() is checked, then
+    possibly existing aliases. In case no FQDN is available, hostname
+    from gethostname() is returned.
+    """
+    name = name.strip()
+    if not name or name == '0.0.0.0':
+        name = gethostname()
+    try:
+        hostname, aliases, ipaddrs = gethostbyaddr(name)
+    except error:
+        pass
+    else:
+        aliases.insert(0, hostname)
+        for name in aliases:
+            if '.' in name:
+                break
+        else:
+            name = hostname
+    return name
+
+
+_GLOBAL_DEFAULT_TIMEOUT = object()
diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c
new file mode 100644 (file)
index 0000000..7cf09a8
--- /dev/null
@@ -0,0 +1,2666 @@
+/*
+ * Copyright (C) Jelmer Vernooij 2005,2008 <jelmer@samba.org>
+ * Copyright (C) Stefan Metzmacher 2006-2009 <metze@samba.org>
+ * Copyright (C) Andreas Schneider 2013 <asn@samba.org>
+ *
+ * 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. Neither the name of the author 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 AUTHOR 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 AUTHOR 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.
+ *
+ */
+
+/*
+   Socket wrapper library. Passes all socket communication over
+   unix domain sockets if the environment variable SOCKET_WRAPPER_DIR
+   is set.
+*/
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
+#include <errno.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#ifndef _PUBLIC_
+#define _PUBLIC_
+#endif
+
+#define SWRAP_DLIST_ADD(list,item) do { \
+       if (!(list)) { \
+               (item)->prev    = NULL; \
+               (item)->next    = NULL; \
+               (list)          = (item); \
+       } else { \
+               (item)->prev    = NULL; \
+               (item)->next    = (list); \
+               (list)->prev    = (item); \
+               (list)          = (item); \
+       } \
+} while (0)
+
+#define SWRAP_DLIST_REMOVE(list,item) do { \
+       if ((list) == (item)) { \
+               (list)          = (item)->next; \
+               if (list) { \
+                       (list)->prev    = NULL; \
+               } \
+       } else { \
+               if ((item)->prev) { \
+                       (item)->prev->next      = (item)->next; \
+               } \
+               if ((item)->next) { \
+                       (item)->next->prev      = (item)->prev; \
+               } \
+       } \
+       (item)->prev    = NULL; \
+       (item)->next    = NULL; \
+} while (0)
+
+#ifdef HAVE_GETTIMEOFDAY_TZ
+#define swrapGetTimeOfDay(tval) gettimeofday(tval,NULL)
+#else
+#define swrapGetTimeOfDay(tval)        gettimeofday(tval)
+#endif
+
+/* we need to use a very terse format here as IRIX 6.4 silently
+   truncates names to 16 chars, so if we use a longer name then we
+   can't tell which port a packet came from with recvfrom() 
+   
+   with this format we have 8 chars left for the directory name
+*/
+#define SOCKET_FORMAT "%c%02X%04X"
+#define SOCKET_TYPE_CHAR_TCP           'T'
+#define SOCKET_TYPE_CHAR_UDP           'U'
+#define SOCKET_TYPE_CHAR_TCP_V6                'X'
+#define SOCKET_TYPE_CHAR_UDP_V6                'Y'
+
+/* This limit is to avoid broadcast sendto() needing to stat too many
+ * files.  It may be raised (with a performance cost) to up to 254
+ * without changing the format above */
+#define MAX_WRAPPED_INTERFACES 40
+
+#include <dlfcn.h>
+
+#define LIBC_NAME "libc.so.6"
+
+static void *libc_hnd;
+
+static int libc_dlopen(void)
+{
+    if (libc_hnd != NULL) {
+        return 0;
+    }
+    libc_hnd = dlopen(LIBC_NAME, RTLD_LAZY);
+    if (libc_hnd == NULL) {
+        printf("Failed to dlopen %s: %s\n", LIBC_NAME, dlerror());
+        exit(-1);
+    }
+
+    return 0;
+}
+
+static void *libc_dlsym(const char *name)
+{
+    void *func;
+
+    libc_dlopen();
+
+    func = dlsym(libc_hnd, name);
+
+    if (func == NULL) {
+        printf("Failed to find %s in %s: %s\n",
+               name, LIBC_NAME, dlerror());
+        exit(-1);
+    }
+
+    return func;
+}
+
+static int (*libc_accept)(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
+
+static int real_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
+{
+    if (libc_accept == NULL) {
+        *(void **)(&libc_accept) = libc_dlsym("accept");
+    }
+
+    return libc_accept(sockfd, addr, addrlen);
+}
+
+#ifdef HAVE_IPV6
+/*
+ * FD00::5357:5FXX
+ */
+static const struct in6_addr *swrap_ipv6(void)
+{
+       static struct in6_addr v;
+       static int initialized;
+       int ret;
+
+       if (initialized) {
+               return &v;
+       }
+       initialized = 1;
+
+       ret = inet_pton(AF_INET6, "FD00::5357:5F00", &v);
+       if (ret <= 0) {
+               abort();
+       }
+
+       return &v;
+}
+#endif
+
+static struct sockaddr *sockaddr_dup(const void *data, socklen_t len)
+{
+       struct sockaddr *ret = (struct sockaddr *)malloc(len);
+       memcpy(ret, data, len);
+       return ret;
+}
+
+static void set_port(int family, int prt, struct sockaddr *addr)
+{
+       switch (family) {
+       case AF_INET:
+               ((struct sockaddr_in *)addr)->sin_port = htons(prt);
+               break;
+#ifdef HAVE_IPV6
+       case AF_INET6:
+               ((struct sockaddr_in6 *)addr)->sin6_port = htons(prt);
+               break;
+#endif
+       }
+}
+
+static size_t socket_length(int family)
+{
+       switch (family) {
+       case AF_INET:
+               return sizeof(struct sockaddr_in);
+#ifdef HAVE_IPV6
+       case AF_INET6:
+               return sizeof(struct sockaddr_in6);
+#endif
+       }
+       return 0;
+}
+
+struct socket_info_fd {
+       struct socket_info_fd *prev, *next;
+       int fd;
+};
+
+struct socket_info
+{
+       struct socket_info_fd *fds;
+
+       int family;
+       int type;
+       int protocol;
+       int bound;
+       int bcast;
+       int is_server;
+       int connected;
+       int defer_connect;
+
+       char *tmp_path;
+
+       struct sockaddr *myname;
+       socklen_t myname_len;
+
+       struct sockaddr *peername;
+       socklen_t peername_len;
+
+       struct {
+               unsigned long pck_snd;
+               unsigned long pck_rcv;
+       } io;
+
+       struct socket_info *prev, *next;
+};
+
+static struct socket_info *sockets;
+
+const char *socket_wrapper_dir(void)
+{
+       const char *s = getenv("SOCKET_WRAPPER_DIR");
+       if (s == NULL) {
+               return NULL;
+       }
+       if (strncmp(s, "./", 2) == 0) {
+               s += 2;
+       }
+       return s;
+}
+
+unsigned int socket_wrapper_default_iface(void)
+{
+       const char *s = getenv("SOCKET_WRAPPER_DEFAULT_IFACE");
+       if (s) {
+               unsigned int iface;
+               if (sscanf(s, "%u", &iface) == 1) {
+                       if (iface >= 1 && iface <= MAX_WRAPPED_INTERFACES) {
+                               return iface;
+                       }
+               }
+       }
+
+       return 1;/* 127.0.0.1 */
+}
+
+static int convert_un_in(const struct sockaddr_un *un, struct sockaddr *in, socklen_t *len)
+{
+       unsigned int iface;
+       unsigned int prt;
+       const char *p;
+       char type;
+
+       p = strrchr(un->sun_path, '/');
+       if (p) p++; else p = un->sun_path;
+
+       if (sscanf(p, SOCKET_FORMAT, &type, &iface, &prt) != 3) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (prt > 0xFFFF) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       switch(type) {
+       case SOCKET_TYPE_CHAR_TCP:
+       case SOCKET_TYPE_CHAR_UDP: {
+               struct sockaddr_in *in2 = (struct sockaddr_in *)(void *)in;
+
+               if ((*len) < sizeof(*in2)) {
+                   errno = EINVAL;
+                   return -1;
+               }
+
+               memset(in2, 0, sizeof(*in2));
+               in2->sin_family = AF_INET;
+               in2->sin_addr.s_addr = htonl((127<<24) | iface);
+               in2->sin_port = htons(prt);
+
+               *len = sizeof(*in2);
+               break;
+       }
+#ifdef HAVE_IPV6
+       case SOCKET_TYPE_CHAR_TCP_V6:
+       case SOCKET_TYPE_CHAR_UDP_V6: {
+               struct sockaddr_in6 *in2 = (struct sockaddr_in6 *)(void *)in;
+
+               if ((*len) < sizeof(*in2)) {
+                       errno = EINVAL;
+                       return -1;
+               }
+
+               memset(in2, 0, sizeof(*in2));
+               in2->sin6_family = AF_INET6;
+               in2->sin6_addr = *swrap_ipv6();
+               in2->sin6_addr.s6_addr[15] = iface;
+               in2->sin6_port = htons(prt);
+
+               *len = sizeof(*in2);
+               break;
+       }
+#endif
+       default:
+               errno = EINVAL;
+               return -1;
+       }
+
+       return 0;
+}
+
+static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un,
+                               int *bcast)
+{
+       char type = '\0';
+       unsigned int prt;
+       unsigned int iface;
+       int is_bcast = 0;
+
+       if (bcast) *bcast = 0;
+
+       switch (inaddr->sa_family) {
+       case AF_INET: {
+               const struct sockaddr_in *in = 
+                   (const struct sockaddr_in *)(const void *)inaddr;
+               unsigned int addr = ntohl(in->sin_addr.s_addr);
+               char u_type = '\0';
+               char b_type = '\0';
+               char a_type = '\0';
+
+               switch (si->type) {
+               case SOCK_STREAM:
+                       u_type = SOCKET_TYPE_CHAR_TCP;
+                       break;
+               case SOCK_DGRAM:
+                       u_type = SOCKET_TYPE_CHAR_UDP;
+                       a_type = SOCKET_TYPE_CHAR_UDP;
+                       b_type = SOCKET_TYPE_CHAR_UDP;
+                       break;
+               }
+
+               prt = ntohs(in->sin_port);
+               if (a_type && addr == 0xFFFFFFFF) {
+                       /* 255.255.255.255 only udp */
+                       is_bcast = 2;
+                       type = a_type;
+                       iface = socket_wrapper_default_iface();
+               } else if (b_type && addr == 0x7FFFFFFF) {
+                       /* 127.255.255.255 only udp */
+                       is_bcast = 1;
+                       type = b_type;
+                       iface = socket_wrapper_default_iface();
+               } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
+                       /* 127.0.0.X */
+                       is_bcast = 0;
+                       type = u_type;
+                       iface = (addr & 0x000000FF);
+               } else {
+                       errno = ENETUNREACH;
+                       return -1;
+               }
+               if (bcast) *bcast = is_bcast;
+               break;
+       }
+#ifdef HAVE_IPV6
+       case AF_INET6: {
+               const struct sockaddr_in6 *in = 
+                   (const struct sockaddr_in6 *)(const void *)inaddr;
+               struct in6_addr cmp1, cmp2;
+
+               switch (si->type) {
+               case SOCK_STREAM:
+                       type = SOCKET_TYPE_CHAR_TCP_V6;
+                       break;
+               case SOCK_DGRAM:
+                       type = SOCKET_TYPE_CHAR_UDP_V6;
+                       break;
+               }
+
+               /* XXX no multicast/broadcast */
+
+               prt = ntohs(in->sin6_port);
+
+               cmp1 = *swrap_ipv6();
+               cmp2 = in->sin6_addr;
+               cmp2.s6_addr[15] = 0;
+               if (IN6_ARE_ADDR_EQUAL(&cmp1, &cmp2)) {
+                       iface = in->sin6_addr.s6_addr[15];
+               } else {
+                       errno = ENETUNREACH;
+                       return -1;
+               }
+
+               break;
+       }
+#endif
+       default:
+               errno = ENETUNREACH;
+               return -1;
+       }
+
+       if (prt == 0) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (is_bcast) {
+               snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL", 
+                        socket_wrapper_dir());
+               /* the caller need to do more processing */
+               return 0;
+       }
+
+       snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, 
+                socket_wrapper_dir(), type, iface, prt);
+
+       return 0;
+}
+
+static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un,
+                              int *bcast)
+{
+       char type = '\0';
+       unsigned int prt;
+       unsigned int iface;
+       struct stat st;
+       int is_bcast = 0;
+
+       if (bcast) *bcast = 0;
+
+       switch (si->family) {
+       case AF_INET: {
+               const struct sockaddr_in *in = 
+                   (const struct sockaddr_in *)(const void *)inaddr;
+               unsigned int addr = ntohl(in->sin_addr.s_addr);
+               char u_type = '\0';
+               char d_type = '\0';
+               char b_type = '\0';
+               char a_type = '\0';
+
+               prt = ntohs(in->sin_port);
+
+               switch (si->type) {
+               case SOCK_STREAM:
+                       u_type = SOCKET_TYPE_CHAR_TCP;
+                       d_type = SOCKET_TYPE_CHAR_TCP;
+                       break;
+               case SOCK_DGRAM:
+                       u_type = SOCKET_TYPE_CHAR_UDP;
+                       d_type = SOCKET_TYPE_CHAR_UDP;
+                       a_type = SOCKET_TYPE_CHAR_UDP;
+                       b_type = SOCKET_TYPE_CHAR_UDP;
+                       break;
+               }
+
+               if (addr == 0) {
+                       /* 0.0.0.0 */
+                       is_bcast = 0;
+                       type = d_type;
+                       iface = socket_wrapper_default_iface();
+               } else if (a_type && addr == 0xFFFFFFFF) {
+                       /* 255.255.255.255 only udp */
+                       is_bcast = 2;
+                       type = a_type;
+                       iface = socket_wrapper_default_iface();
+               } else if (b_type && addr == 0x7FFFFFFF) {
+                       /* 127.255.255.255 only udp */
+                       is_bcast = 1;
+                       type = b_type;
+                       iface = socket_wrapper_default_iface();
+               } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
+                       /* 127.0.0.X */
+                       is_bcast = 0;
+                       type = u_type;
+                       iface = (addr & 0x000000FF);
+               } else {
+                       errno = EADDRNOTAVAIL;
+                       return -1;
+               }
+               break;
+       }
+#ifdef HAVE_IPV6
+       case AF_INET6: {
+               const struct sockaddr_in6 *in = 
+                   (const struct sockaddr_in6 *)(const void *)inaddr;
+               struct in6_addr cmp1, cmp2;
+
+               switch (si->type) {
+               case SOCK_STREAM:
+                       type = SOCKET_TYPE_CHAR_TCP_V6;
+                       break;
+               case SOCK_DGRAM:
+                       type = SOCKET_TYPE_CHAR_UDP_V6;
+                       break;
+               }
+
+               /* XXX no multicast/broadcast */
+
+               prt = ntohs(in->sin6_port);
+
+               cmp1 = *swrap_ipv6();
+               cmp2 = in->sin6_addr;
+               cmp2.s6_addr[15] = 0;
+               if (IN6_IS_ADDR_UNSPECIFIED(&in->sin6_addr)) {
+                       iface = socket_wrapper_default_iface();
+               } else if (IN6_ARE_ADDR_EQUAL(&cmp1, &cmp2)) {
+                       iface = in->sin6_addr.s6_addr[15];
+               } else {
+                       errno = EADDRNOTAVAIL;
+                       return -1;
+               }
+
+               break;
+       }
+#endif
+       default:
+               errno = EADDRNOTAVAIL;
+               return -1;
+       }
+
+
+       if (bcast) *bcast = is_bcast;
+
+       if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (prt == 0) {
+               /* handle auto-allocation of ephemeral ports */
+               for (prt = 5001; prt < 10000; prt++) {
+                       snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, 
+                                socket_wrapper_dir(), type, iface, prt);
+                       if (stat(un->sun_path, &st) == 0) continue;
+
+                       set_port(si->family, prt, si->myname);
+                       break;
+               }
+               if (prt == 10000) {
+                       errno = ENFILE;
+                       return -1;
+               }
+       }
+
+       snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, 
+                socket_wrapper_dir(), type, iface, prt);
+       return 0;
+}
+
+static struct socket_info *find_socket_info(int fd)
+{
+       struct socket_info *i;
+       for (i = sockets; i; i = i->next) {
+               struct socket_info_fd *f;
+               for (f = i->fds; f; f = f->next) {
+                       if (f->fd == fd) {
+                               return i;
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+static int sockaddr_convert_to_un(struct socket_info *si, const struct sockaddr *in_addr, socklen_t in_len, 
+                                 struct sockaddr_un *out_addr, int alloc_sock, int *bcast)
+{
+       struct sockaddr *out = (struct sockaddr *)(void *)out_addr;
+       if (!out_addr)
+               return 0;
+
+       out->sa_family = AF_UNIX;
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+       out->sa_len = sizeof(*out_addr);
+#endif
+
+       switch (in_addr->sa_family) {
+       case AF_INET:
+#ifdef HAVE_IPV6
+       case AF_INET6:
+#endif
+               switch (si->type) {
+               case SOCK_STREAM:
+               case SOCK_DGRAM:
+                       break;
+               default:
+                       errno = ESOCKTNOSUPPORT;
+                       return -1;
+               }
+               if (alloc_sock) {
+                       return convert_in_un_alloc(si, in_addr, out_addr, bcast);
+               } else {
+                       return convert_in_un_remote(si, in_addr, out_addr, bcast);
+               }
+       default:
+               break;
+       }
+
+       errno = EAFNOSUPPORT;
+       return -1;
+}
+
+static int sockaddr_convert_from_un(const struct socket_info *si, 
+                                   const struct sockaddr_un *in_addr, 
+                                   socklen_t un_addrlen,
+                                   int family,
+                                   struct sockaddr *out_addr,
+                                   socklen_t *out_addrlen)
+{
+       int ret;
+
+       if (out_addr == NULL || out_addrlen == NULL) 
+               return 0;
+
+       if (un_addrlen == 0) {
+               *out_addrlen = 0;
+               return 0;
+       }
+
+       switch (family) {
+       case AF_INET:
+#ifdef HAVE_IPV6
+       case AF_INET6:
+#endif
+               switch (si->type) {
+               case SOCK_STREAM:
+               case SOCK_DGRAM:
+                       break;
+               default:
+                       errno = ESOCKTNOSUPPORT;
+                       return -1;
+               }
+               ret = convert_un_in(in_addr, out_addr, out_addrlen);
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+               out_addr->sa_len = *out_addrlen;
+#endif
+               return ret;
+       default:
+               break;
+       }
+
+       errno = EAFNOSUPPORT;
+       return -1;
+}
+
+enum swrap_packet_type {
+       SWRAP_CONNECT_SEND,
+       SWRAP_CONNECT_UNREACH,
+       SWRAP_CONNECT_RECV,
+       SWRAP_CONNECT_ACK,
+       SWRAP_ACCEPT_SEND,
+       SWRAP_ACCEPT_RECV,
+       SWRAP_ACCEPT_ACK,
+       SWRAP_RECVFROM,
+       SWRAP_SENDTO,
+       SWRAP_SENDTO_UNREACH,
+       SWRAP_PENDING_RST,
+       SWRAP_RECV,
+       SWRAP_RECV_RST,
+       SWRAP_SEND,
+       SWRAP_SEND_RST,
+       SWRAP_CLOSE_SEND,
+       SWRAP_CLOSE_RECV,
+       SWRAP_CLOSE_ACK,
+};
+
+struct swrap_file_hdr {
+       uint32_t        magic;
+       uint16_t        version_major;
+       uint16_t        version_minor;
+       int32_t         timezone;
+       uint32_t        sigfigs;
+       uint32_t        frame_max_len;
+#define SWRAP_FRAME_LENGTH_MAX 0xFFFF
+       uint32_t        link_type;
+};
+#define SWRAP_FILE_HDR_SIZE 24
+
+struct swrap_packet_frame {
+       uint32_t seconds;
+       uint32_t micro_seconds;
+       uint32_t recorded_length;
+       uint32_t full_length;
+};
+#define SWRAP_PACKET_FRAME_SIZE 16
+
+union swrap_packet_ip {
+       struct {
+               uint8_t         ver_hdrlen;
+               uint8_t         tos;
+               uint16_t        packet_length;
+               uint16_t        identification;
+               uint8_t         flags;
+               uint8_t         fragment;
+               uint8_t         ttl;
+               uint8_t         protocol;
+               uint16_t        hdr_checksum;
+               uint32_t        src_addr;
+               uint32_t        dest_addr;
+       } v4;
+#define SWRAP_PACKET_IP_V4_SIZE 20
+       struct {
+               uint8_t         ver_prio;
+               uint8_t         flow_label_high;
+               uint16_t        flow_label_low;
+               uint16_t        payload_length;
+               uint8_t         next_header;
+               uint8_t         hop_limit;
+               uint8_t         src_addr[16];
+               uint8_t         dest_addr[16];
+       } v6;
+#define SWRAP_PACKET_IP_V6_SIZE 40
+};
+#define SWRAP_PACKET_IP_SIZE 40
+
+union swrap_packet_payload {
+       struct {
+               uint16_t        source_port;
+               uint16_t        dest_port;
+               uint32_t        seq_num;
+               uint32_t        ack_num;
+               uint8_t         hdr_length;
+               uint8_t         control;
+               uint16_t        window;
+               uint16_t        checksum;
+               uint16_t        urg;
+       } tcp;
+#define SWRAP_PACKET_PAYLOAD_TCP_SIZE 20
+       struct {
+               uint16_t        source_port;
+               uint16_t        dest_port;
+               uint16_t        length;
+               uint16_t        checksum;
+       } udp;
+#define SWRAP_PACKET_PAYLOAD_UDP_SIZE 8
+       struct {
+               uint8_t         type;
+               uint8_t         code;
+               uint16_t        checksum;
+               uint32_t        unused;
+       } icmp4;
+#define SWRAP_PACKET_PAYLOAD_ICMP4_SIZE 8
+       struct {
+               uint8_t         type;
+               uint8_t         code;
+               uint16_t        checksum;
+               uint32_t        unused;
+       } icmp6;
+#define SWRAP_PACKET_PAYLOAD_ICMP6_SIZE 8
+};
+#define SWRAP_PACKET_PAYLOAD_SIZE 20
+
+#define SWRAP_PACKET_MIN_ALLOC \
+       (SWRAP_PACKET_FRAME_SIZE + \
+        SWRAP_PACKET_IP_SIZE + \
+        SWRAP_PACKET_PAYLOAD_SIZE)
+
+static const char *socket_wrapper_pcap_file(void)
+{
+       static int initialized = 0;
+       static const char *s = NULL;
+       static const struct swrap_file_hdr h;
+       static const struct swrap_packet_frame f;
+       static const union swrap_packet_ip i;
+       static const union swrap_packet_payload p;
+
+       if (initialized == 1) {
+               return s;
+       }
+       initialized = 1;
+
+       /*
+        * TODO: don't use the structs use plain buffer offsets
+        *       and PUSH_U8(), PUSH_U16() and PUSH_U32()
+        * 
+        * for now make sure we disable PCAP support
+        * if the struct has alignment!
+        */
+       if (sizeof(h) != SWRAP_FILE_HDR_SIZE) {
+               return NULL;
+       }
+       if (sizeof(f) != SWRAP_PACKET_FRAME_SIZE) {
+               return NULL;
+       }
+       if (sizeof(i) != SWRAP_PACKET_IP_SIZE) {
+               return NULL;
+       }
+       if (sizeof(i.v4) != SWRAP_PACKET_IP_V4_SIZE) {
+               return NULL;
+       }
+       if (sizeof(i.v6) != SWRAP_PACKET_IP_V6_SIZE) {
+               return NULL;
+       }
+       if (sizeof(p) != SWRAP_PACKET_PAYLOAD_SIZE) {
+               return NULL;
+       }
+       if (sizeof(p.tcp) != SWRAP_PACKET_PAYLOAD_TCP_SIZE) {
+               return NULL;
+       }
+       if (sizeof(p.udp) != SWRAP_PACKET_PAYLOAD_UDP_SIZE) {
+               return NULL;
+       }
+       if (sizeof(p.icmp4) != SWRAP_PACKET_PAYLOAD_ICMP4_SIZE) {
+               return NULL;
+       }
+       if (sizeof(p.icmp6) != SWRAP_PACKET_PAYLOAD_ICMP6_SIZE) {
+               return NULL;
+       }
+
+       s = getenv("SOCKET_WRAPPER_PCAP_FILE");
+       if (s == NULL) {
+               return NULL;
+       }
+       if (strncmp(s, "./", 2) == 0) {
+               s += 2;
+       }
+       return s;
+}
+
+static uint8_t *swrap_packet_init(struct timeval *tval,
+                                 const struct sockaddr *src,
+                                 const struct sockaddr *dest,
+                                 int socket_type,
+                                 const uint8_t *payload,
+                                 size_t payload_len,
+                                 unsigned long tcp_seqno,
+                                 unsigned long tcp_ack,
+                                 unsigned char tcp_ctl,
+                                 int unreachable,
+                                 size_t *_packet_len)
+{
+       uint8_t *base;
+       uint8_t *buf;
+       struct swrap_packet_frame *frame;
+       union swrap_packet_ip *ip;
+       union swrap_packet_payload *pay;
+       size_t packet_len;
+       size_t alloc_len;
+       size_t nonwire_len = sizeof(*frame);
+       size_t wire_hdr_len = 0;
+       size_t wire_len = 0;
+       size_t ip_hdr_len = 0;
+       size_t icmp_hdr_len = 0;
+       size_t icmp_truncate_len = 0;
+       uint8_t protocol = 0, icmp_protocol = 0;
+       const struct sockaddr_in *src_in = NULL;
+       const struct sockaddr_in *dest_in = NULL;
+#ifdef HAVE_IPV6
+       const struct sockaddr_in6 *src_in6 = NULL;
+       const struct sockaddr_in6 *dest_in6 = NULL;
+#endif
+       uint16_t src_port;
+       uint16_t dest_port;
+
+       switch (src->sa_family) {
+       case AF_INET:
+               src_in = (const struct sockaddr_in *)src;
+               dest_in = (const struct sockaddr_in *)dest;
+               src_port = src_in->sin_port;
+               dest_port = dest_in->sin_port;
+               ip_hdr_len = sizeof(ip->v4);
+               break;
+#ifdef HAVE_IPV6
+       case AF_INET6:
+               src_in6 = (const struct sockaddr_in6 *)src;
+               dest_in6 = (const struct sockaddr_in6 *)dest;
+               src_port = src_in6->sin6_port;
+               dest_port = dest_in6->sin6_port;
+               ip_hdr_len = sizeof(ip->v6);
+               break;
+#endif
+       default:
+               return NULL;
+       }
+
+       switch (socket_type) {
+       case SOCK_STREAM:
+               protocol = 0x06; /* TCP */
+               wire_hdr_len = ip_hdr_len + sizeof(pay->tcp);
+               wire_len = wire_hdr_len + payload_len;
+               break;
+
+       case SOCK_DGRAM:
+               protocol = 0x11; /* UDP */
+               wire_hdr_len = ip_hdr_len + sizeof(pay->udp);
+               wire_len = wire_hdr_len + payload_len;
+               break;
+
+       default:
+               return NULL;
+       }
+
+       if (unreachable) {
+               icmp_protocol = protocol;
+               switch (src->sa_family) {
+               case AF_INET:
+                       protocol = 0x01; /* ICMPv4 */
+                       icmp_hdr_len = ip_hdr_len + sizeof(pay->icmp4);
+                       break;
+#ifdef HAVE_IPV6
+               case AF_INET6:
+                       protocol = 0x3A; /* ICMPv6 */
+                       icmp_hdr_len = ip_hdr_len + sizeof(pay->icmp6);
+                       break;
+#endif
+               }
+               if (wire_len > 64 ) {
+                       icmp_truncate_len = wire_len - 64;
+               }
+               wire_hdr_len += icmp_hdr_len;
+               wire_len += icmp_hdr_len;
+       }
+
+       packet_len = nonwire_len + wire_len;
+       alloc_len = packet_len;
+       if (alloc_len < SWRAP_PACKET_MIN_ALLOC) {
+               alloc_len = SWRAP_PACKET_MIN_ALLOC;
+       }
+
+       base = (uint8_t *)malloc(alloc_len);
+       if (!base) return NULL;
+
+       buf = base;
+
+       frame = (struct swrap_packet_frame *)buf;
+       frame->seconds          = tval->tv_sec;
+       frame->micro_seconds    = tval->tv_usec;
+       frame->recorded_length  = wire_len - icmp_truncate_len;
+       frame->full_length      = wire_len - icmp_truncate_len;
+       buf += SWRAP_PACKET_FRAME_SIZE;
+
+       ip = (union swrap_packet_ip *)buf;
+       switch (src->sa_family) {
+       case AF_INET:
+               ip->v4.ver_hdrlen       = 0x45; /* version 4 and 5 * 32 bit words */
+               ip->v4.tos              = 0x00;
+               ip->v4.packet_length    = htons(wire_len - icmp_truncate_len);
+               ip->v4.identification   = htons(0xFFFF);
+               ip->v4.flags            = 0x40; /* BIT 1 set - means don't fraqment */
+               ip->v4.fragment         = htons(0x0000);
+               ip->v4.ttl              = 0xFF;
+               ip->v4.protocol         = protocol;
+               ip->v4.hdr_checksum     = htons(0x0000);
+               ip->v4.src_addr         = src_in->sin_addr.s_addr;
+               ip->v4.dest_addr        = dest_in->sin_addr.s_addr;
+               buf += SWRAP_PACKET_IP_V4_SIZE;
+               break;
+#ifdef HAVE_IPV6
+       case AF_INET6:
+               ip->v6.ver_prio         = 0x60; /* version 4 and 5 * 32 bit words */
+               ip->v6.flow_label_high  = 0x00;
+               ip->v6.flow_label_low   = 0x0000;
+               ip->v6.payload_length   = htons(wire_len - icmp_truncate_len); /* TODO */
+               ip->v6.next_header      = protocol;
+               memcpy(ip->v6.src_addr, src_in6->sin6_addr.s6_addr, 16);
+               memcpy(ip->v6.dest_addr, dest_in6->sin6_addr.s6_addr, 16);
+               buf += SWRAP_PACKET_IP_V6_SIZE;
+               break;
+#endif
+       }
+
+       if (unreachable) {
+               pay = (union swrap_packet_payload *)buf;
+               switch (src->sa_family) {
+               case AF_INET:
+                       pay->icmp4.type         = 0x03; /* destination unreachable */
+                       pay->icmp4.code         = 0x01; /* host unreachable */
+                       pay->icmp4.checksum     = htons(0x0000);
+                       pay->icmp4.unused       = htonl(0x00000000);
+                       buf += SWRAP_PACKET_PAYLOAD_ICMP4_SIZE;
+
+                       /* set the ip header in the ICMP payload */
+                       ip = (union swrap_packet_ip *)buf;
+                       ip->v4.ver_hdrlen       = 0x45; /* version 4 and 5 * 32 bit words */
+                       ip->v4.tos              = 0x00;
+                       ip->v4.packet_length    = htons(wire_len - icmp_hdr_len);
+                       ip->v4.identification   = htons(0xFFFF);
+                       ip->v4.flags            = 0x40; /* BIT 1 set - means don't fraqment */
+                       ip->v4.fragment         = htons(0x0000);
+                       ip->v4.ttl              = 0xFF;
+                       ip->v4.protocol         = icmp_protocol;
+                       ip->v4.hdr_checksum     = htons(0x0000);
+                       ip->v4.src_addr         = dest_in->sin_addr.s_addr;
+                       ip->v4.dest_addr        = src_in->sin_addr.s_addr;
+                       buf += SWRAP_PACKET_IP_V4_SIZE;
+
+                       src_port = dest_in->sin_port;
+                       dest_port = src_in->sin_port;
+                       break;
+#ifdef HAVE_IPV6
+               case AF_INET6:
+                       pay->icmp6.type         = 0x01; /* destination unreachable */
+                       pay->icmp6.code         = 0x03; /* address unreachable */
+                       pay->icmp6.checksum     = htons(0x0000);
+                       pay->icmp6.unused       = htonl(0x00000000);
+                       buf += SWRAP_PACKET_PAYLOAD_ICMP6_SIZE;
+
+                       /* set the ip header in the ICMP payload */
+                       ip = (union swrap_packet_ip *)buf;
+                       ip->v6.ver_prio         = 0x60; /* version 4 and 5 * 32 bit words */
+                       ip->v6.flow_label_high  = 0x00;
+                       ip->v6.flow_label_low   = 0x0000;
+                       ip->v6.payload_length   = htons(wire_len - icmp_truncate_len); /* TODO */
+                       ip->v6.next_header      = protocol;
+                       memcpy(ip->v6.src_addr, dest_in6->sin6_addr.s6_addr, 16);
+                       memcpy(ip->v6.dest_addr, src_in6->sin6_addr.s6_addr, 16);
+                       buf += SWRAP_PACKET_IP_V6_SIZE;
+
+                       src_port = dest_in6->sin6_port;
+                       dest_port = src_in6->sin6_port;
+                       break;
+#endif
+               }
+       }
+
+       pay = (union swrap_packet_payload *)buf;
+
+       switch (socket_type) {
+       case SOCK_STREAM:
+               pay->tcp.source_port    = src_port;
+               pay->tcp.dest_port      = dest_port;
+               pay->tcp.seq_num        = htonl(tcp_seqno);
+               pay->tcp.ack_num        = htonl(tcp_ack);
+               pay->tcp.hdr_length     = 0x50; /* 5 * 32 bit words */
+               pay->tcp.control        = tcp_ctl;
+               pay->tcp.window         = htons(0x7FFF);
+               pay->tcp.checksum       = htons(0x0000);
+               pay->tcp.urg            = htons(0x0000);
+               buf += SWRAP_PACKET_PAYLOAD_TCP_SIZE;
+
+               break;
+
+       case SOCK_DGRAM:
+               pay->udp.source_port    = src_port;
+               pay->udp.dest_port      = dest_port;
+               pay->udp.length         = htons(8 + payload_len);
+               pay->udp.checksum       = htons(0x0000);
+               buf += SWRAP_PACKET_PAYLOAD_UDP_SIZE;
+
+               break;
+       }
+
+       if (payload && payload_len > 0) {
+               memcpy(buf, payload, payload_len);
+       }
+
+       *_packet_len = packet_len - icmp_truncate_len;
+       return base;
+}
+
+static int swrap_get_pcap_fd(const char *fname)
+{
+       static int fd = -1;
+
+       if (fd != -1) return fd;
+
+       fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0644);
+       if (fd != -1) {
+               struct swrap_file_hdr file_hdr;
+               file_hdr.magic          = 0xA1B2C3D4;
+               file_hdr.version_major  = 0x0002;       
+               file_hdr.version_minor  = 0x0004;
+               file_hdr.timezone       = 0x00000000;
+               file_hdr.sigfigs        = 0x00000000;
+               file_hdr.frame_max_len  = SWRAP_FRAME_LENGTH_MAX;
+               file_hdr.link_type      = 0x0065; /* 101 RAW IP */
+
+               if (write(fd, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) {
+                       close(fd);
+                       fd = -1;
+               }
+               return fd;
+       }
+
+       fd = open(fname, O_WRONLY|O_APPEND, 0644);
+
+       return fd;
+}
+
+static uint8_t *swrap_marshall_packet(struct socket_info *si,
+                                     const struct sockaddr *addr,
+                                     enum swrap_packet_type type,
+                                     const void *buf, size_t len,
+                                     size_t *packet_len)
+{
+       const struct sockaddr *src_addr;
+       const struct sockaddr *dest_addr;
+       unsigned long tcp_seqno = 0;
+       unsigned long tcp_ack = 0;
+       unsigned char tcp_ctl = 0;
+       int unreachable = 0;
+
+       struct timeval tv;
+
+       switch (si->family) {
+       case AF_INET:
+               break;
+#ifdef HAVE_IPV6
+       case AF_INET6:
+               break;
+#endif
+       default:
+               return NULL;
+       }
+
+       switch (type) {
+       case SWRAP_CONNECT_SEND:
+               if (si->type != SOCK_STREAM) return NULL;
+
+               src_addr = si->myname;
+               dest_addr = addr;
+
+               tcp_seqno = si->io.pck_snd;
+               tcp_ack = si->io.pck_rcv;
+               tcp_ctl = 0x02; /* SYN */
+
+               si->io.pck_snd += 1;
+
+               break;
+
+       case SWRAP_CONNECT_RECV:
+               if (si->type != SOCK_STREAM) return NULL;
+
+               dest_addr = si->myname;
+               src_addr = addr;
+
+               tcp_seqno = si->io.pck_rcv;
+               tcp_ack = si->io.pck_snd;
+               tcp_ctl = 0x12; /** SYN,ACK */
+
+               si->io.pck_rcv += 1;
+
+               break;
+
+       case SWRAP_CONNECT_UNREACH:
+               if (si->type != SOCK_STREAM) return NULL;
+
+               dest_addr = si->myname;
+               src_addr = addr;
+
+               /* Unreachable: resend the data of SWRAP_CONNECT_SEND */
+               tcp_seqno = si->io.pck_snd - 1;
+               tcp_ack = si->io.pck_rcv;
+               tcp_ctl = 0x02; /* SYN */
+               unreachable = 1;
+
+               break;
+
+       case SWRAP_CONNECT_ACK:
+               if (si->type != SOCK_STREAM) return NULL;
+
+               src_addr = si->myname;
+               dest_addr = addr;
+
+               tcp_seqno = si->io.pck_snd;
+               tcp_ack = si->io.pck_rcv;
+               tcp_ctl = 0x10; /* ACK */
+
+               break;
+
+       case SWRAP_ACCEPT_SEND:
+               if (si->type != SOCK_STREAM) return NULL;
+
+               dest_addr = si->myname;
+               src_addr = addr;
+
+               tcp_seqno = si->io.pck_rcv;
+               tcp_ack = si->io.pck_snd;
+               tcp_ctl = 0x02; /* SYN */
+
+               si->io.pck_rcv += 1;
+
+               break;
+
+       case SWRAP_ACCEPT_RECV:
+               if (si->type != SOCK_STREAM) return NULL;
+
+               src_addr = si->myname;
+               dest_addr = addr;
+
+               tcp_seqno = si->io.pck_snd;
+               tcp_ack = si->io.pck_rcv;
+               tcp_ctl = 0x12; /* SYN,ACK */
+
+               si->io.pck_snd += 1;
+
+               break;
+
+       case SWRAP_ACCEPT_ACK:
+               if (si->type != SOCK_STREAM) return NULL;
+
+               dest_addr = si->myname;
+               src_addr = addr;
+
+               tcp_seqno = si->io.pck_rcv;
+               tcp_ack = si->io.pck_snd;
+               tcp_ctl = 0x10; /* ACK */
+
+               break;
+
+       case SWRAP_SEND:
+               src_addr = si->myname;
+               dest_addr = si->peername;
+
+               tcp_seqno = si->io.pck_snd;
+               tcp_ack = si->io.pck_rcv;
+               tcp_ctl = 0x18; /* PSH,ACK */
+
+               si->io.pck_snd += len;
+
+               break;
+
+       case SWRAP_SEND_RST:
+               dest_addr = si->myname;
+               src_addr = si->peername;
+
+               if (si->type == SOCK_DGRAM) {
+                       return swrap_marshall_packet(si, si->peername,
+                                         SWRAP_SENDTO_UNREACH,
+                                         buf, len, packet_len);
+               }
+
+               tcp_seqno = si->io.pck_rcv;
+               tcp_ack = si->io.pck_snd;
+               tcp_ctl = 0x14; /** RST,ACK */
+
+               break;
+
+       case SWRAP_PENDING_RST:
+               dest_addr = si->myname;
+               src_addr = si->peername;
+
+               if (si->type == SOCK_DGRAM) {
+                       return NULL;
+               }
+
+               tcp_seqno = si->io.pck_rcv;
+               tcp_ack = si->io.pck_snd;
+               tcp_ctl = 0x14; /* RST,ACK */
+
+               break;
+
+       case SWRAP_RECV:
+               dest_addr = si->myname;
+               src_addr = si->peername;
+
+               tcp_seqno = si->io.pck_rcv;
+               tcp_ack = si->io.pck_snd;
+               tcp_ctl = 0x18; /* PSH,ACK */
+
+               si->io.pck_rcv += len;
+
+               break;
+
+       case SWRAP_RECV_RST:
+               dest_addr = si->myname;
+               src_addr = si->peername;
+
+               if (si->type == SOCK_DGRAM) {
+                       return NULL;
+               }
+
+               tcp_seqno = si->io.pck_rcv;
+               tcp_ack = si->io.pck_snd;
+               tcp_ctl = 0x14; /* RST,ACK */
+
+               break;
+
+       case SWRAP_SENDTO:
+               src_addr = si->myname;
+               dest_addr = addr;
+
+               si->io.pck_snd += len;
+
+               break;
+
+       case SWRAP_SENDTO_UNREACH:
+               dest_addr = si->myname;
+               src_addr = addr;
+
+               unreachable = 1;
+
+               break;
+
+       case SWRAP_RECVFROM:
+               dest_addr = si->myname;
+               src_addr = addr;
+
+               si->io.pck_rcv += len;
+
+               break;
+
+       case SWRAP_CLOSE_SEND:
+               if (si->type != SOCK_STREAM) return NULL;
+
+               src_addr = si->myname;
+               dest_addr = si->peername;
+
+               tcp_seqno = si->io.pck_snd;
+               tcp_ack = si->io.pck_rcv;
+               tcp_ctl = 0x11; /* FIN, ACK */
+
+               si->io.pck_snd += 1;
+
+               break;
+
+       case SWRAP_CLOSE_RECV:
+               if (si->type != SOCK_STREAM) return NULL;
+
+               dest_addr = si->myname;
+               src_addr = si->peername;
+
+               tcp_seqno = si->io.pck_rcv;
+               tcp_ack = si->io.pck_snd;
+               tcp_ctl = 0x11; /* FIN,ACK */
+
+               si->io.pck_rcv += 1;
+
+               break;
+
+       case SWRAP_CLOSE_ACK:
+               if (si->type != SOCK_STREAM) return NULL;
+
+               src_addr = si->myname;
+               dest_addr = si->peername;
+
+               tcp_seqno = si->io.pck_snd;
+               tcp_ack = si->io.pck_rcv;
+               tcp_ctl = 0x10; /* ACK */
+
+               break;
+       default:
+               return NULL;
+       }
+
+       swrapGetTimeOfDay(&tv);
+
+       return swrap_packet_init(&tv, src_addr, dest_addr, si->type,
+                                (const uint8_t *)buf, len,
+                                tcp_seqno, tcp_ack, tcp_ctl, unreachable,
+                                packet_len);
+}
+
+static void swrap_dump_packet(struct socket_info *si,
+                             const struct sockaddr *addr,
+                             enum swrap_packet_type type,
+                             const void *buf, size_t len)
+{
+       const char *file_name;
+       uint8_t *packet;
+       size_t packet_len = 0;
+       int fd;
+
+       file_name = socket_wrapper_pcap_file();
+       if (!file_name) {
+               return;
+       }
+
+       packet = swrap_marshall_packet(si, addr, type, buf, len, &packet_len);
+       if (!packet) {
+               return;
+       }
+
+       fd = swrap_get_pcap_fd(file_name);
+       if (fd != -1) {
+               if (write(fd, packet, packet_len) != packet_len) {
+                       free(packet);
+                       return;
+               }
+       }
+
+       free(packet);
+}
+
+_PUBLIC_ int swrap_socket(int family, int type, int protocol)
+{
+       struct socket_info *si;
+       struct socket_info_fd *fi;
+       int fd;
+       int real_type = type;
+#ifdef SOCK_CLOEXEC
+       real_type &= ~SOCK_CLOEXEC;
+#endif
+#ifdef SOCK_NONBLOCK
+       real_type &= ~SOCK_NONBLOCK;
+#endif
+
+       if (!socket_wrapper_dir()) {
+               return real_socket(family, type, protocol);
+       }
+
+       switch (family) {
+       case AF_INET:
+#ifdef HAVE_IPV6
+       case AF_INET6:
+#endif
+               break;
+       case AF_UNIX:
+               return real_socket(family, type, protocol);
+       default:
+               errno = EAFNOSUPPORT;
+               return -1;
+       }
+
+       switch (real_type) {
+       case SOCK_STREAM:
+               break;
+       case SOCK_DGRAM:
+               break;
+       default:
+               errno = EPROTONOSUPPORT;
+               return -1;
+       }
+
+       switch (protocol) {
+       case 0:
+               break;
+       case 6:
+               if (real_type == SOCK_STREAM) {
+                       break;
+               }
+               /*fall through*/
+       case 17:
+               if (real_type == SOCK_DGRAM) {
+                       break;
+               }
+               /*fall through*/
+       default:
+               errno = EPROTONOSUPPORT;
+               return -1;
+       }
+
+       /* We must call real_socket with type, from the caller, not the version we removed
+          SOCK_CLOEXEC and SOCK_NONBLOCK from */
+       fd = real_socket(AF_UNIX, type, 0);
+
+       if (fd == -1) return -1;
+
+       si = (struct socket_info *)calloc(1, sizeof(struct socket_info));
+       if (si == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       si->family = family;
+
+       /* however, the rest of the socket_wrapper code expects just
+        * the type, not the flags */
+       si->type = real_type;
+       si->protocol = protocol;
+
+       fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
+       if (fi == NULL) {
+               free(si);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       fi->fd = fd;
+
+       SWRAP_DLIST_ADD(si->fds, fi);
+       SWRAP_DLIST_ADD(sockets, si);
+
+       return fd;
+}
+
+_PUBLIC_ int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
+{
+       struct socket_info *parent_si, *child_si;
+       struct socket_info_fd *child_fi;
+       int fd;
+       struct sockaddr_un un_addr;
+       socklen_t un_addrlen = sizeof(un_addr);
+       struct sockaddr_un un_my_addr;
+       socklen_t un_my_addrlen = sizeof(un_my_addr);
+       struct sockaddr *my_addr;
+       socklen_t my_addrlen, len;
+       int ret;
+
+       parent_si = find_socket_info(s);
+       if (!parent_si) {
+               return real_accept(s, addr, addrlen);
+       }
+
+       /* 
+        * assume out sockaddr have the same size as the in parent
+        * socket family
+        */
+       my_addrlen = socket_length(parent_si->family);
+       if (my_addrlen <= 0) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       my_addr = (struct sockaddr *)malloc(my_addrlen);
+       if (my_addr == NULL) {
+               return -1;
+       }
+
+       memset(&un_addr, 0, sizeof(un_addr));
+       memset(&un_my_addr, 0, sizeof(un_my_addr));
+
+       ret = real_accept(s, (struct sockaddr *)(void *)&un_addr, &un_addrlen);
+       if (ret == -1) {
+               free(my_addr);
+               return ret;
+       }
+
+       fd = ret;
+
+       len = my_addrlen;
+       ret = sockaddr_convert_from_un(parent_si, &un_addr, un_addrlen,
+                                      parent_si->family, my_addr, &len);
+       if (ret == -1) {
+               free(my_addr);
+               close(fd);
+               return ret;
+       }
+
+       child_si = (struct socket_info *)malloc(sizeof(struct socket_info));
+       memset(child_si, 0, sizeof(*child_si));
+
+       child_fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
+       if (child_fi == NULL) {
+               free(child_si);
+               free(my_addr);
+               close(fd);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       child_fi->fd = fd;
+
+       SWRAP_DLIST_ADD(child_si->fds, child_fi);
+
+       child_si->family = parent_si->family;
+       child_si->type = parent_si->type;
+       child_si->protocol = parent_si->protocol;
+       child_si->bound = 1;
+       child_si->is_server = 1;
+       child_si->connected = 1;
+
+       child_si->peername_len = len;
+       child_si->peername = sockaddr_dup(my_addr, len);
+
+       if (addr != NULL && addrlen != NULL) {
+               size_t copy_len = MIN(*addrlen, len);
+               if (copy_len > 0) {
+                       memcpy(addr, my_addr, copy_len);
+               }
+               *addrlen = len;
+       }
+
+       ret = real_getsockname(fd, (struct sockaddr *)(void *)&un_my_addr,
+                              &un_my_addrlen);
+       if (ret == -1) {
+               free(child_fi);
+               free(child_si);
+               close(fd);
+               return ret;
+       }
+
+       len = my_addrlen;
+       ret = sockaddr_convert_from_un(child_si, &un_my_addr, un_my_addrlen,
+                                      child_si->family, my_addr, &len);
+       if (ret == -1) {
+               free(child_fi);
+               free(child_si);
+               free(my_addr);
+               close(fd);
+               return ret;
+       }
+
+       child_si->myname_len = len;
+       child_si->myname = sockaddr_dup(my_addr, len);
+       free(my_addr);
+
+       SWRAP_DLIST_ADD(sockets, child_si);
+
+       swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_SEND, NULL, 0);
+       swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_RECV, NULL, 0);
+       swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_ACK, NULL, 0);
+
+       return fd;
+}
+
+static int autobind_start_init;
+static int autobind_start;
+
+/* using sendto() or connect() on an unbound socket would give the
+   recipient no way to reply, as unlike UDP and TCP, a unix domain
+   socket can't auto-assign emphemeral port numbers, so we need to
+   assign it here.
+   Note: this might change the family from ipv6 to ipv4
+*/
+static int swrap_auto_bind(int fd, struct socket_info *si, int family)
+{
+       struct sockaddr_un un_addr;
+       int i;
+       char type;
+       int ret;
+       int port;
+       struct stat st;
+
+       if (autobind_start_init != 1) {
+               autobind_start_init = 1;
+               autobind_start = getpid();
+               autobind_start %= 50000;
+               autobind_start += 10000;
+       }
+
+       un_addr.sun_family = AF_UNIX;
+
+       switch (family) {
+       case AF_INET: {
+               struct sockaddr_in in;
+
+               switch (si->type) {
+               case SOCK_STREAM:
+                       type = SOCKET_TYPE_CHAR_TCP;
+                       break;
+               case SOCK_DGRAM:
+                       type = SOCKET_TYPE_CHAR_UDP;
+                       break;
+               default:
+                   errno = ESOCKTNOSUPPORT;
+                   return -1;
+               }
+
+               memset(&in, 0, sizeof(in));
+               in.sin_family = AF_INET;
+               in.sin_addr.s_addr = htonl(127<<24 | 
+                                          socket_wrapper_default_iface());
+
+               si->myname_len = sizeof(in);
+               si->myname = sockaddr_dup(&in, si->myname_len);
+               break;
+       }
+#ifdef HAVE_IPV6
+       case AF_INET6: {
+               struct sockaddr_in6 in6;
+
+               if (si->family != family) {
+                       errno = ENETUNREACH;
+                       return -1;
+               }
+
+               switch (si->type) {
+               case SOCK_STREAM:
+                       type = SOCKET_TYPE_CHAR_TCP_V6;
+                       break;
+               case SOCK_DGRAM:
+                       type = SOCKET_TYPE_CHAR_UDP_V6;
+                       break;
+               default:
+                       errno = ESOCKTNOSUPPORT;
+                       return -1;
+               }
+
+               memset(&in6, 0, sizeof(in6));
+               in6.sin6_family = AF_INET6;
+               in6.sin6_addr = *swrap_ipv6();
+               in6.sin6_addr.s6_addr[15] = socket_wrapper_default_iface();
+               si->myname_len = sizeof(in6);
+               si->myname = sockaddr_dup(&in6, si->myname_len);
+               break;
+       }
+#endif
+       default:
+               errno = ESOCKTNOSUPPORT;
+               return -1;
+       }
+
+       if (autobind_start > 60000) {
+               autobind_start = 10000;
+       }
+
+       for (i=0;i<1000;i++) {
+               port = autobind_start + i;
+               snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), 
+                        "%s/"SOCKET_FORMAT, socket_wrapper_dir(),
+                        type, socket_wrapper_default_iface(), port);
+               if (stat(un_addr.sun_path, &st) == 0) continue;
+
+               ret = real_bind(fd, (struct sockaddr *)(void *)&un_addr,
+                               sizeof(un_addr));
+               if (ret == -1) return ret;
+
+               si->tmp_path = strdup(un_addr.sun_path);
+               si->bound = 1;
+               autobind_start = port + 1;
+               break;
+       }
+       if (i == 1000) {
+               errno = ENFILE;
+               return -1;
+       }
+
+       si->family = family;
+       set_port(si->family, port, si->myname);
+
+       return 0;
+}
+
+
+_PUBLIC_ int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen)
+{
+       int ret;
+       struct sockaddr_un un_addr;
+       struct socket_info *si = find_socket_info(s);
+       int bcast = 0;
+
+       if (!si) {
+               return real_connect(s, serv_addr, addrlen);
+       }
+
+       if (si->bound == 0) {
+               ret = swrap_auto_bind(s, si, serv_addr->sa_family);
+               if (ret == -1) return -1;
+       }
+
+       if (si->family != serv_addr->sa_family) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       ret = sockaddr_convert_to_un(si, serv_addr,
+                                    addrlen, &un_addr, 0, &bcast);
+       if (ret == -1) return -1;
+
+       if (bcast) {
+               errno = ENETUNREACH;
+               return -1;
+       }
+
+       if (si->type == SOCK_DGRAM) {
+               si->defer_connect = 1;
+               ret = 0;
+       } else {
+               swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_SEND, NULL, 0);
+
+               ret = real_connect(s, (struct sockaddr *)(void *)&un_addr,
+                                  sizeof(struct sockaddr_un));
+       }
+
+       /* to give better errors */
+       if (ret == -1 && errno == ENOENT) {
+               errno = EHOSTUNREACH;
+       }
+
+       if (ret == 0) {
+               si->peername_len = addrlen;
+               si->peername = sockaddr_dup(serv_addr, addrlen);
+               si->connected = 1;
+
+               swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_RECV, NULL, 0);
+               swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_ACK, NULL, 0);
+       } else {
+               swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_UNREACH, NULL, 0);
+       }
+
+       return ret;
+}
+
+_PUBLIC_ int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
+{
+       int ret;
+       struct sockaddr_un un_addr;
+       struct socket_info *si = find_socket_info(s);
+
+       if (!si) {
+               return real_bind(s, myaddr, addrlen);
+       }
+
+       si->myname_len = addrlen;
+       si->myname = sockaddr_dup(myaddr, addrlen);
+
+       ret = sockaddr_convert_to_un(si, myaddr, addrlen, &un_addr, 1, &si->bcast);
+       if (ret == -1) return -1;
+
+       unlink(un_addr.sun_path);
+
+       ret = real_bind(s, (struct sockaddr *)(void *)&un_addr,
+                       sizeof(struct sockaddr_un));
+
+       if (ret == 0) {
+               si->bound = 1;
+       }
+
+       return ret;
+}
+
+_PUBLIC_ int swrap_listen(int s, int backlog)
+{
+       int ret;
+       struct socket_info *si = find_socket_info(s);
+
+       if (!si) {
+               return real_listen(s, backlog);
+       }
+
+       ret = real_listen(s, backlog);
+
+       return ret;
+}
+
+_PUBLIC_ int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen)
+{
+       struct socket_info *si = find_socket_info(s);
+
+       if (!si) {
+               return real_getpeername(s, name, addrlen);
+       }
+
+       if (!si->peername)
+       {
+               errno = ENOTCONN;
+               return -1;
+       }
+
+       memcpy(name, si->peername, si->peername_len);
+       *addrlen = si->peername_len;
+
+       return 0;
+}
+
+_PUBLIC_ int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen)
+{
+       struct socket_info *si = find_socket_info(s);
+
+       if (!si) {
+               return real_getsockname(s, name, addrlen);
+       }
+
+       memcpy(name, si->myname, si->myname_len);
+       *addrlen = si->myname_len;
+
+       return 0;
+}
+
+_PUBLIC_ int swrap_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
+{
+       struct socket_info *si = find_socket_info(s);
+
+       if (!si) {
+               return real_getsockopt(s, level, optname, optval, optlen);
+       }
+
+       if (level == SOL_SOCKET) {
+               return real_getsockopt(s, level, optname, optval, optlen);
+       } 
+
+       errno = ENOPROTOOPT;
+       return -1;
+}
+
+_PUBLIC_ int swrap_setsockopt(int s, int  level,  int  optname,  const  void  *optval, socklen_t optlen)
+{
+       struct socket_info *si = find_socket_info(s);
+
+       if (!si) {
+               return real_setsockopt(s, level, optname, optval, optlen);
+       }
+
+       if (level == SOL_SOCKET) {
+               return real_setsockopt(s, level, optname, optval, optlen);
+       }
+
+       switch (si->family) {
+       case AF_INET:
+               return 0;
+#ifdef HAVE_IPV6
+       case AF_INET6:
+               return 0;
+#endif
+       default:
+               errno = ENOPROTOOPT;
+               return -1;
+       }
+}
+
+_PUBLIC_ int swrap_ioctl(int s, int r, void *p)
+{
+       int ret;
+       struct socket_info *si = find_socket_info(s);
+       int value;
+
+       if (!si) {
+               return real_ioctl(s, r, p);
+       }
+
+       ret = real_ioctl(s, r, p);
+
+       switch (r) {
+       case FIONREAD:
+               value = *((int *)p);
+               if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
+                       swrap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
+               } else if (value == 0) { /* END OF FILE */
+                       swrap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
+               }
+               break;
+       }
+
+       return ret;
+}
+
+static ssize_t swrap_sendmsg_before(int fd,
+                                   struct socket_info *si,
+                                   struct msghdr *msg,
+                                   struct iovec *tmp_iov,
+                                   struct sockaddr_un *tmp_un,
+                                   const struct sockaddr_un **to_un,
+                                   const struct sockaddr **to,
+                                   int *bcast)
+{
+       size_t i, len = 0;
+       ssize_t ret;
+
+       if (to_un) {
+               *to_un = NULL;
+       }
+       if (to) {
+               *to = NULL;
+       }
+       if (bcast) {
+               *bcast = 0;
+       }
+
+       switch (si->type) {
+       case SOCK_STREAM:
+               if (!si->connected) {
+                       errno = ENOTCONN;
+                       return -1;
+               }
+
+               if (msg->msg_iovlen == 0) {
+                       break;
+               }
+
+               /*
+                * cut down to 1500 byte packets for stream sockets,
+                * which makes it easier to format PCAP capture files
+                * (as the caller will simply continue from here)
+                */
+
+               for (i=0; i < msg->msg_iovlen; i++) {
+                       size_t nlen;
+                       nlen = len + msg->msg_iov[i].iov_len;
+                       if (nlen > 1500) {
+                               break;
+                       }
+               }
+               msg->msg_iovlen = i;
+               if (msg->msg_iovlen == 0) {
+                       *tmp_iov = msg->msg_iov[0];
+                       tmp_iov->iov_len = MIN(tmp_iov->iov_len, 1500);
+                       msg->msg_iov = tmp_iov;
+                       msg->msg_iovlen = 1;
+               }
+               break;
+
+       case SOCK_DGRAM:
+               if (si->connected) {
+                       if (msg->msg_name) {
+                               errno = EISCONN;
+                               return -1;
+                       }
+               } else {
+                       const struct sockaddr *msg_name;
+                       msg_name = (const struct sockaddr *)msg->msg_name;
+
+                       if (msg_name == NULL) {
+                               errno = ENOTCONN;
+                               return -1;
+                       }
+
+
+                       ret = sockaddr_convert_to_un(si, msg_name, msg->msg_namelen,
+                                                    tmp_un, 0, bcast);
+                       if (ret == -1) return -1;
+
+                       if (to_un) {
+                               *to_un = tmp_un;
+                       }
+                       if (to) {
+                               *to = msg_name;
+                       }
+                       msg->msg_name = tmp_un;
+                       msg->msg_namelen = sizeof(*tmp_un);
+               }
+
+               if (si->bound == 0) {
+                       ret = swrap_auto_bind(fd, si, si->family);
+                       if (ret == -1) return -1;
+               }
+
+               if (!si->defer_connect) {
+                       break;
+               }
+
+               ret = sockaddr_convert_to_un(si, si->peername, si->peername_len,
+                                            tmp_un, 0, NULL);
+               if (ret == -1) return -1;
+
+               ret = real_connect(fd, (struct sockaddr *)(void *)tmp_un,
+                                  sizeof(*tmp_un));
+
+               /* to give better errors */
+               if (ret == -1 && errno == ENOENT) {
+                       errno = EHOSTUNREACH;
+               }
+
+               if (ret == -1) {
+                       return ret;
+               }
+
+               si->defer_connect = 0;
+               break;
+       default:
+               errno = EHOSTUNREACH;
+               return -1;
+       }
+
+       return 0;
+}
+
+static void swrap_sendmsg_after(struct socket_info *si,
+                               struct msghdr *msg,
+                               const struct sockaddr *to,
+                               ssize_t ret)
+{
+       int saved_errno = errno;
+       size_t i, len = 0;
+       uint8_t *buf;
+       off_t ofs = 0;
+       size_t avail = 0;
+       size_t remain;
+
+       /* to give better errors */
+       if (ret == -1 && saved_errno == ENOENT) {
+               saved_errno = EHOSTUNREACH;
+       }
+
+       for (i=0; i < msg->msg_iovlen; i++) {
+               avail += msg->msg_iov[i].iov_len;
+       }
+
+       if (ret == -1) {
+               remain = MIN(80, avail);
+       } else {
+               remain = ret;
+       }
+
+       /* we capture it as one single packet */
+       buf = (uint8_t *)malloc(remain);
+       if (!buf) {
+               /* we just not capture the packet */
+               errno = saved_errno;
+               return;
+       }
+
+       for (i=0; i < msg->msg_iovlen; i++) {
+               size_t this_time = MIN(remain, msg->msg_iov[i].iov_len);
+               memcpy(buf + ofs,
+                      msg->msg_iov[i].iov_base,
+                      this_time);
+               ofs += this_time;
+               remain -= this_time;
+       }
+       len = ofs;
+
+       switch (si->type) {
+       case SOCK_STREAM:
+               if (ret == -1) {
+                       swrap_dump_packet(si, NULL, SWRAP_SEND, buf, len);
+                       swrap_dump_packet(si, NULL, SWRAP_SEND_RST, NULL, 0);
+               } else {
+                       swrap_dump_packet(si, NULL, SWRAP_SEND, buf, len);
+               }
+               break;
+
+       case SOCK_DGRAM:
+               if (si->connected) {
+                       to = si->peername;
+               }
+               if (ret == -1) {
+                       swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
+                       swrap_dump_packet(si, to, SWRAP_SENDTO_UNREACH, buf, len);
+               } else {
+                       swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
+               }
+               break;
+       }
+
+       free(buf);
+       errno = saved_errno;
+}
+
+_PUBLIC_ ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
+{
+       struct sockaddr_un un_addr;
+       socklen_t un_addrlen = sizeof(un_addr);
+       int ret;
+       struct socket_info *si = find_socket_info(s);
+       struct sockaddr_storage ss;
+       socklen_t ss_len = sizeof(ss);
+
+       if (!si) {
+               return real_recvfrom(s, buf, len, flags, from, fromlen);
+       }
+
+       if (!from) {
+               from = (struct sockaddr *)(void *)&ss;
+               fromlen = &ss_len;
+       }
+
+       if (si->type == SOCK_STREAM) {
+               /* cut down to 1500 byte packets for stream sockets,
+                * which makes it easier to format PCAP capture files
+                * (as the caller will simply continue from here) */
+               len = MIN(len, 1500);
+       }
+
+       /* irix 6.4 forgets to null terminate the sun_path string :-( */
+       memset(&un_addr, 0, sizeof(un_addr));
+       ret = real_recvfrom(s, buf, len, flags,
+                           (struct sockaddr *)(void *)&un_addr, &un_addrlen);
+       if (ret == -1) 
+               return ret;
+
+       if (sockaddr_convert_from_un(si, &un_addr, un_addrlen,
+                                    si->family, from, fromlen) == -1) {
+               return -1;
+       }
+
+       swrap_dump_packet(si, from, SWRAP_RECVFROM, buf, ret);
+
+       return ret;
+}
+
+
+_PUBLIC_ ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
+{
+       struct msghdr msg;
+       struct iovec tmp;
+       struct sockaddr_un un_addr;
+       const struct sockaddr_un *to_un = NULL;
+       ssize_t ret;
+       struct socket_info *si = find_socket_info(s);
+       int bcast = 0;
+
+       if (!si) {
+               return real_sendto(s, buf, len, flags, to, tolen);
+       }
+
+       tmp.iov_base = discard_const_p(char, buf);
+       tmp.iov_len = len;
+
+       ZERO_STRUCT(msg);
+       msg.msg_name = discard_const_p(struct sockaddr, to); /* optional address */
+       msg.msg_namelen = tolen;       /* size of address */
+       msg.msg_iov = &tmp;            /* scatter/gather array */
+       msg.msg_iovlen = 1;            /* # elements in msg_iov */
+#if 0 /* not available on solaris */
+       msg.msg_control = NULL;        /* ancillary data, see below */
+       msg.msg_controllen = 0;        /* ancillary data buffer len */
+       msg.msg_flags = 0;             /* flags on received message */
+#endif
+
+       ret = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, &to_un, &to, &bcast);
+       if (ret == -1) return -1;
+
+       buf = msg.msg_iov[0].iov_base;
+       len = msg.msg_iov[0].iov_len;
+
+       if (bcast) {
+               struct stat st;
+               unsigned int iface;
+               unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
+               char type;
+
+               type = SOCKET_TYPE_CHAR_UDP;
+
+               for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
+                       snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT,
+                                socket_wrapper_dir(), type, iface, prt);
+                       if (stat(un_addr.sun_path, &st) != 0) continue;
+
+                       /* ignore the any errors in broadcast sends */
+                       real_sendto(s, buf, len, flags,
+                                   (struct sockaddr *)(void *)&un_addr,
+                                   sizeof(un_addr));
+               }
+
+               swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
+
+               return len;
+       }
+
+       ret = real_sendto(s, buf, len, flags, (struct sockaddr *)msg.msg_name,
+                         msg.msg_namelen);
+
+       swrap_sendmsg_after(si, &msg, to, ret);
+
+       return ret;
+}
+
+_PUBLIC_ ssize_t swrap_recv(int s, void *buf, size_t len, int flags)
+{
+       int ret;
+       struct socket_info *si = find_socket_info(s);
+
+       if (!si) {
+               return real_recv(s, buf, len, flags);
+       }
+
+       if (si->type == SOCK_STREAM) {
+               /* cut down to 1500 byte packets for stream sockets,
+                * which makes it easier to format PCAP capture files
+                * (as the caller will simply continue from here) */
+               len = MIN(len, 1500);
+       }
+
+       ret = real_recv(s, buf, len, flags);
+       if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
+               swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
+       } else if (ret == 0) { /* END OF FILE */
+               swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
+       } else if (ret > 0) {
+               swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
+       }
+
+       return ret;
+}
+
+_PUBLIC_ ssize_t swrap_read(int s, void *buf, size_t len)
+{
+       int ret;
+       struct socket_info *si = find_socket_info(s);
+
+       if (!si) {
+               return real_read(s, buf, len);
+       }
+
+       if (si->type == SOCK_STREAM) {
+               /* cut down to 1500 byte packets for stream sockets,
+                * which makes it easier to format PCAP capture files
+                * (as the caller will simply continue from here) */
+               len = MIN(len, 1500);
+       }
+
+       ret = real_read(s, buf, len);
+       if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
+               swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
+       } else if (ret == 0) { /* END OF FILE */
+               swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
+       } else if (ret > 0) {
+               swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
+       }
+
+       return ret;
+}
+
+
+_PUBLIC_ ssize_t swrap_send(int s, const void *buf, size_t len, int flags)
+{
+       struct msghdr msg;
+       struct iovec tmp;
+       struct sockaddr_un un_addr;
+       ssize_t ret;
+       struct socket_info *si = find_socket_info(s);
+
+       if (!si) {
+               return real_send(s, buf, len, flags);
+       }
+
+       tmp.iov_base = discard_const_p(char, buf);
+       tmp.iov_len = len;
+
+       ZERO_STRUCT(msg);
+       msg.msg_name = NULL;           /* optional address */
+       msg.msg_namelen = 0;           /* size of address */
+       msg.msg_iov = &tmp;            /* scatter/gather array */
+       msg.msg_iovlen = 1;            /* # elements in msg_iov */
+#if 0 /* not available on solaris */
+       msg.msg_control = NULL;        /* ancillary data, see below */
+       msg.msg_controllen = 0;        /* ancillary data buffer len */
+       msg.msg_flags = 0;             /* flags on received message */
+#endif
+
+       ret = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, NULL, NULL, NULL);
+       if (ret == -1) return -1;
+
+       buf = msg.msg_iov[0].iov_base;
+       len = msg.msg_iov[0].iov_len;
+
+       ret = real_send(s, buf, len, flags);
+
+       swrap_sendmsg_after(si, &msg, NULL, ret);
+
+       return ret;
+}
+
+_PUBLIC_ ssize_t swrap_sendmsg(int s, const struct msghdr *omsg, int flags)
+{
+       struct msghdr msg;
+       struct iovec tmp;
+       struct sockaddr_un un_addr;
+       const struct sockaddr_un *to_un = NULL;
+       const struct sockaddr *to = NULL;
+       ssize_t ret;
+       struct socket_info *si = find_socket_info(s);
+       int bcast = 0;
+
+       if (!si) {
+               return real_sendmsg(s, omsg, flags);
+       }
+
+       tmp.iov_base = NULL;
+       tmp.iov_len = 0;
+
+       msg = *omsg;
+#if 0
+       msg.msg_name = omsg->msg_name;             /* optional address */
+       msg.msg_namelen = omsg->msg_namelen;       /* size of address */
+       msg.msg_iov = omsg->msg_iov;               /* scatter/gather array */
+       msg.msg_iovlen = omsg->msg_iovlen;         /* # elements in msg_iov */
+       /* the following is not available on solaris */
+       msg.msg_control = omsg->msg_control;       /* ancillary data, see below */
+       msg.msg_controllen = omsg->msg_controllen; /* ancillary data buffer len */
+       msg.msg_flags = omsg->msg_flags;           /* flags on received message */
+#endif
+
+       ret = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, &to_un, &to, &bcast);
+       if (ret == -1) return -1;
+
+       if (bcast) {
+               struct stat st;
+               unsigned int iface;
+               unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
+               char type;
+               size_t i, len = 0;
+               uint8_t *buf;
+               off_t ofs = 0;
+               size_t avail = 0;
+               size_t remain;
+
+               for (i=0; i < msg.msg_iovlen; i++) {
+                       avail += msg.msg_iov[i].iov_len;
+               }
+
+               len = avail;
+               remain = avail;
+
+               /* we capture it as one single packet */
+               buf = (uint8_t *)malloc(remain);
+               if (!buf) {
+                       return -1;
+               }
+
+               for (i=0; i < msg.msg_iovlen; i++) {
+                       size_t this_time = MIN(remain, msg.msg_iov[i].iov_len);
+                       memcpy(buf + ofs,
+                              msg.msg_iov[i].iov_base,
+                              this_time);
+                       ofs += this_time;
+                       remain -= this_time;
+               }
+
+               type = SOCKET_TYPE_CHAR_UDP;
+
+               for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
+                       snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT,
+                                socket_wrapper_dir(), type, iface, prt);
+                       if (stat(un_addr.sun_path, &st) != 0) continue;
+
+                       msg.msg_name = &un_addr;           /* optional address */
+                       msg.msg_namelen = sizeof(un_addr); /* size of address */
+
+                       /* ignore the any errors in broadcast sends */
+                       real_sendmsg(s, &msg, flags);
+               }
+
+               swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
+               free(buf);
+
+               return len;
+       }
+
+       ret = real_sendmsg(s, &msg, flags);
+
+       swrap_sendmsg_after(si, &msg, to, ret);
+
+       return ret;
+}
+
+int swrap_readv(int s, const struct iovec *vector, size_t count)
+{
+       int ret;
+       struct socket_info *si = find_socket_info(s);
+       struct iovec v;
+
+       if (!si) {
+               return real_readv(s, vector, count);
+       }
+
+       if (!si->connected) {
+               errno = ENOTCONN;
+               return -1;
+       }
+
+       if (si->type == SOCK_STREAM && count > 0) {
+               /* cut down to 1500 byte packets for stream sockets,
+                * which makes it easier to format PCAP capture files
+                * (as the caller will simply continue from here) */
+               size_t i, len = 0;
+
+               for (i=0; i < count; i++) {
+                       size_t nlen;
+                       nlen = len + vector[i].iov_len;
+                       if (nlen > 1500) {
+                               break;
+                       }
+               }
+               count = i;
+               if (count == 0) {
+                       v = vector[0];
+                       v.iov_len = MIN(v.iov_len, 1500);
+                       vector = &v;
+                       count = 1;
+               }
+       }
+
+       ret = real_readv(s, vector, count);
+       if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
+               swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
+       } else if (ret == 0) { /* END OF FILE */
+               swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
+       } else if (ret > 0) {
+               uint8_t *buf;
+               off_t ofs = 0;
+               size_t i;
+               size_t remain = ret;
+
+               /* we capture it as one single packet */
+               buf = (uint8_t *)malloc(ret);
+               if (!buf) {
+                       /* we just not capture the packet */
+                       errno = 0;
+                       return ret;
+               }
+
+               for (i=0; i < count; i++) {
+                       size_t this_time = MIN(remain, vector[i].iov_len);
+                       memcpy(buf + ofs,
+                              vector[i].iov_base,
+                              this_time);
+                       ofs += this_time;
+                       remain -= this_time;
+               }
+
+               swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
+               free(buf);
+       }
+
+       return ret;
+}
+
+ssize_t swrap_writev(int s, const struct iovec *vector, size_t count)
+{
+       struct msghdr msg;
+       struct iovec tmp;
+       struct sockaddr_un un_addr;
+       ssize_t ret;
+       struct socket_info *si = find_socket_info(s);
+
+       if (!si) {
+               return real_writev(s, vector, count);
+       }
+
+       tmp.iov_base = NULL;
+       tmp.iov_len = 0;
+
+       ZERO_STRUCT(msg);
+       msg.msg_name = NULL;           /* optional address */
+       msg.msg_namelen = 0;           /* size of address */
+       msg.msg_iov = discard_const_p(struct iovec, vector); /* scatter/gather array */
+       msg.msg_iovlen = count;        /* # elements in msg_iov */
+#if 0 /* not available on solaris */
+       msg.msg_control = NULL;        /* ancillary data, see below */
+       msg.msg_controllen = 0;        /* ancillary data buffer len */
+       msg.msg_flags = 0;             /* flags on received message */
+#endif
+
+       ret = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, NULL, NULL, NULL);
+       if (ret == -1) return -1;
+
+       ret = real_writev(s, msg.msg_iov, msg.msg_iovlen);
+
+       swrap_sendmsg_after(si, &msg, NULL, ret);
+
+       return ret;
+}
+
+_PUBLIC_ int swrap_close(int fd)
+{
+       struct socket_info *si = find_socket_info(fd);
+       struct socket_info_fd *fi;
+       int ret;
+
+       if (!si) {
+               return real_close(fd);
+       }
+
+       for (fi = si->fds; fi; fi = fi->next) {
+               if (fi->fd == fd) {
+                       SWRAP_DLIST_REMOVE(si->fds, fi);
+                       free(fi);
+                       break;
+               }
+       }
+
+       if (si->fds) {
+               /* there are still references left */
+               return real_close(fd);
+       }
+
+       SWRAP_DLIST_REMOVE(sockets, si);
+
+       if (si->myname && si->peername) {
+               swrap_dump_packet(si, NULL, SWRAP_CLOSE_SEND, NULL, 0);
+       }
+
+       ret = real_close(fd);
+
+       if (si->myname && si->peername) {
+               swrap_dump_packet(si, NULL, SWRAP_CLOSE_RECV, NULL, 0);
+               swrap_dump_packet(si, NULL, SWRAP_CLOSE_ACK, NULL, 0);
+       }
+
+       if (si->myname) free(si->myname);
+       if (si->peername) free(si->peername);
+       if (si->tmp_path) {
+               unlink(si->tmp_path);
+               free(si->tmp_path);
+       }
+       free(si);
+
+       return ret;
+}
+
+_PUBLIC_ int swrap_dup(int fd)
+{
+       struct socket_info *si;
+       struct socket_info_fd *fi;
+
+       si = find_socket_info(fd);
+
+       if (!si) {
+               return real_dup(fd);
+       }
+
+       fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
+       if (fi == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       fi->fd = real_dup(fd);
+       if (fi->fd == -1) {
+               int saved_errno = errno;
+               free(fi);
+               errno = saved_errno;
+               return -1;
+       }
+
+       SWRAP_DLIST_ADD(si->fds, fi);
+       return fi->fd;
+}
+
+_PUBLIC_ int swrap_dup2(int fd, int newfd)
+{
+       struct socket_info *si;
+       struct socket_info_fd *fi;
+
+       si = find_socket_info(fd);
+
+       if (!si) {
+               return real_dup2(fd, newfd);
+       }
+
+       if (find_socket_info(newfd)) {
+               /* dup2() does an implicit close of newfd, which we
+                * need to emulate */
+               swrap_close(newfd);
+       }
+
+       fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
+       if (fi == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       fi->fd = real_dup2(fd, newfd);
+       if (fi->fd == -1) {
+               int saved_errno = errno;
+               free(fi);
+               errno = saved_errno;
+               return -1;
+       }
+
+       SWRAP_DLIST_ADD(si->fds, fi);
+       return fi->fd;
+}
diff --git a/src/socket_wrapper.h b/src/socket_wrapper.h
new file mode 100644 (file)
index 0000000..0b5a6f5
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) Jelmer Vernooij 2005 <jelmer@samba.org>
+ * Copyright (C) Stefan Metzmacher 2006 <metze@samba.org>
+ *
+ * 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. Neither the name of the author 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 AUTHOR 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 AUTHOR 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.
+ *
+ */
+
+#ifndef __SOCKET_WRAPPER_H__
+#define __SOCKET_WRAPPER_H__
+
+const char *socket_wrapper_dir(void);
+unsigned int socket_wrapper_default_iface(void);
+int swrap_socket(int family, int type, int protocol);
+int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
+int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen);
+int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen);
+int swrap_listen(int s, int backlog);
+int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen);
+int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen);
+int swrap_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen);
+int swrap_setsockopt(int s, int  level,  int  optname,  const  void  *optval, socklen_t optlen);
+ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
+ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen);
+ssize_t swrap_sendmsg(int s, const struct msghdr *msg, int flags);
+ssize_t swrap_recvmsg(int s, struct msghdr *msg, int flags);
+int swrap_ioctl(int s, int req, void *ptr);
+ssize_t swrap_recv(int s, void *buf, size_t len, int flags);
+ssize_t swrap_read(int s, void *buf, size_t len);
+ssize_t swrap_send(int s, const void *buf, size_t len, int flags);
+int swrap_readv(int s, const struct iovec *vector, size_t count);
+ssize_t swrap_writev(int s, const struct iovec *vector, size_t count);
+int swrap_close(int);
+int swrap_dup(int oldfd);
+int swrap_dup2(int oldfd, int newfd);
+
+#ifdef SOCKET_WRAPPER_REPLACE
+
+#ifdef accept
+#undef accept
+#endif
+#define accept(s,addr,addrlen)         swrap_accept(s,addr,addrlen)
+
+#ifdef connect
+#undef connect
+#endif
+#define connect(s,serv_addr,addrlen)   swrap_connect(s,serv_addr,addrlen)
+
+#ifdef bind
+#undef bind
+#endif
+#define bind(s,myaddr,addrlen)         swrap_bind(s,myaddr,addrlen)
+
+#ifdef listen
+#undef listen
+#endif
+#define listen(s,blog)                 swrap_listen(s,blog)
+
+#ifdef getpeername
+#undef getpeername
+#endif
+#define getpeername(s,name,addrlen)    swrap_getpeername(s,name,addrlen)
+
+#ifdef getsockname
+#undef getsockname
+#endif
+#define getsockname(s,name,addrlen)    swrap_getsockname(s,name,addrlen)
+
+#ifdef getsockopt
+#undef getsockopt
+#endif
+#define getsockopt(s,level,optname,optval,optlen) swrap_getsockopt(s,level,optname,optval,optlen)
+
+#ifdef setsockopt
+#undef setsockopt
+#endif
+#define setsockopt(s,level,optname,optval,optlen) swrap_setsockopt(s,level,optname,optval,optlen)
+
+#ifdef recvfrom
+#undef recvfrom
+#endif
+#define recvfrom(s,buf,len,flags,from,fromlen)           swrap_recvfrom(s,buf,len,flags,from,fromlen)
+
+#ifdef sendto
+#undef sendto
+#endif
+#define sendto(s,buf,len,flags,to,tolen)          swrap_sendto(s,buf,len,flags,to,tolen)
+
+#ifdef sendmsg
+#undef sendmsg
+#endif
+#define sendmsg(s,msg,flags)            swrap_sendmsg(s,msg,flags)
+
+#ifdef recvmsg
+#undef recvmsg
+#endif
+#define recvmsg(s,msg,flags)            swrap_recvmsg(s,msg,flags)
+
+#ifdef ioctl
+#undef ioctl
+#endif
+#define ioctl(s,req,ptr)               swrap_ioctl(s,req,ptr)
+
+#ifdef recv
+#undef recv
+#endif
+#define recv(s,buf,len,flags)          swrap_recv(s,buf,len,flags)
+
+#ifdef read
+#undef read
+#endif
+#define read(s,buf,len)                swrap_read(s,buf,len)
+
+#ifdef send
+#undef send
+#endif
+#define send(s,buf,len,flags)          swrap_send(s,buf,len,flags)
+
+#ifdef readv
+#undef readv
+#endif
+#define readv(s, vector, count)                swrap_readv(s,vector, count)
+
+#ifdef writev
+#undef writev
+#endif
+#define writev(s, vector, count)       swrap_writev(s,vector, count)
+
+#ifdef socket
+#undef socket
+#endif
+#define socket(domain,type,protocol)   swrap_socket(domain,type,protocol)
+
+#ifdef close
+#undef close
+#endif
+#define close(s)                       swrap_close(s)
+
+#ifdef dup
+#undef dup
+#endif
+#define dup(s)                 swrap_dup(s)
+
+#ifdef dup2
+#undef dup2
+#endif
+#define dup2(s, s2)            swrap_dup2(s, s2)
+
+#endif /* SOCKET_WRAPPER_REPLACE */
+#endif /* __SOCKET_WRAPPER_H__ */
diff --git a/tests/testsuite.c b/tests/testsuite.c
new file mode 100644 (file)
index 0000000..9274e7f
--- /dev/null
@@ -0,0 +1,105 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   local testing of the socket wrapper
+
+   Copyright (C) Jelmer Vernooij 2007
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program 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 General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/network.h"
+#include "../socket_wrapper/socket_wrapper.h"
+#include "torture/torture.h"
+
+static char *old_dir = NULL;
+static char *old_iface = NULL;
+
+static void backup_env(void)
+{
+       old_dir = getenv("SOCKET_WRAPPER_DIR");
+       old_iface = getenv("SOCKET_WRAPPER_DEFAULT_IFACE");
+}
+
+static void restore_env(void)
+{
+       if (old_dir == NULL)
+               unsetenv("SOCKET_WRAPPER_DIR");
+       else
+               setenv("SOCKET_WRAPPER_DIR", old_dir, 1);
+       if (old_iface == NULL)
+               unsetenv("SOCKET_WRAPPER_DEFAULT_IFACE");
+       else
+               setenv("SOCKET_WRAPPER_DEFAULT_IFACE", old_iface, 1);
+}
+
+static bool test_socket_wrapper_dir(struct torture_context *tctx)
+{
+       backup_env();
+
+       setenv("SOCKET_WRAPPER_DIR", "foo", 1);
+       torture_assert_str_equal(tctx, socket_wrapper_dir(), "foo", "setting failed");
+       setenv("SOCKET_WRAPPER_DIR", "./foo", 1);
+       torture_assert_str_equal(tctx, socket_wrapper_dir(), "foo", "setting failed");
+       unsetenv("SOCKET_WRAPPER_DIR");
+       torture_assert_str_equal(tctx, socket_wrapper_dir(), NULL, "resetting failed");
+
+       restore_env();
+
+       return true;
+}
+
+static bool test_swrap_socket(struct torture_context *tctx)
+{
+       backup_env();
+       setenv("SOCKET_WRAPPER_DIR", "foo", 1);
+
+       torture_assert_int_equal(tctx, swrap_socket(1337, 1337, 0), -1, "unknown address family fails");
+       torture_assert_int_equal(tctx, errno, EAFNOSUPPORT, "correct errno set");
+       torture_assert_int_equal(tctx, swrap_socket(AF_INET, 1337, 0), -1, "unknown type fails");
+       torture_assert_int_equal(tctx, errno, EPROTONOSUPPORT, "correct errno set");
+       torture_assert_int_equal(tctx, swrap_socket(AF_INET, SOCK_DGRAM, 10), -1, "unknown protocol fails");
+       torture_assert_int_equal(tctx, errno, EPROTONOSUPPORT, "correct errno set");
+
+       restore_env();
+
+       return true;
+}
+
+unsigned int socket_wrapper_default_iface(void);
+static bool test_socket_wrapper_default_iface(struct torture_context *tctx)
+{
+       backup_env();
+       unsetenv("SOCKET_WRAPPER_DEFAULT_IFACE");
+       torture_assert_int_equal(tctx, socket_wrapper_default_iface(), 1, "unset");
+       setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "2", 1);
+       torture_assert_int_equal(tctx, socket_wrapper_default_iface(), 2, "unset");
+       setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "bla", 1);
+       torture_assert_int_equal(tctx, socket_wrapper_default_iface(), 1, "unset");
+       restore_env();
+       return true;
+}
+
+struct torture_suite *torture_local_socket_wrapper(TALLOC_CTX *mem_ctx)
+{
+       struct torture_suite *suite = torture_suite_create(mem_ctx, 
+                                                                                                          "socket-wrapper");
+
+       torture_suite_add_simple_test(suite, "socket_wrapper_dir", test_socket_wrapper_dir);
+       torture_suite_add_simple_test(suite, "socket", test_swrap_socket);
+       torture_suite_add_simple_test(suite, "socket_wrapper_default_iface", test_socket_wrapper_default_iface);
+
+       return suite;
+}