aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorshrinivasan ganapathy <shrinivasanganapathy@gmail.com>2017-08-11 12:14:05 -0700
committershrinivasan ganapathy <shrinivasanganapathy@gmail.com>2017-08-17 10:36:00 -0700
commite1b749ab40f057bc5098a882b60e3a20da1cf1f9 (patch)
treeb8a9b4d7b435da05f28fb0f5198ad03403c49292
parente6f61ec6c384d68cc3623f6a1070d9234eeed610 (diff)
VCL-LDPRELOAD LIBRARY
A LD_PRELOAD library built on top of VCL library - initial creation. - User can LD_PRELOAD any application that uses POSIX socket API and yet reap the benifits of VPP transport. - addressed review comments - fix bug in vcom_select rv was always zero. - updated README.md with instructions to use socket_test.sh script Signed-off-by: shrinivasan ganapathy <shrinivasanganapathy@gmail.com> new file: vcl-ldpreload/LICENSE new file: vcl-ldpreload/MAINTAINERS new file: vcl-ldpreload/src/Makefile.am new file: vcl-ldpreload/src/configure.ac new file: vcl-ldpreload/src/libvcl-ldpreload.am new file: vcl-ldpreload/src/libvcl-ldpreload/TODO new file: vcl-ldpreload/src/libvcl-ldpreload/vcom.c new file: vcl-ldpreload/src/libvcl-ldpreload/vcom.h new file: vcl-ldpreload/src/libvcl-ldpreload/vcom_glibc_socket.h new file: vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.c new file: vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.h new file: vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.c new file: vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.h new file: vcl-ldpreload/src/vcl-ldpreload.mk new file: vcl-ldpreload/test/README.md Change-Id: I0db70bc4c3b3bac35451afa432c20dc04cb9699c Signed-off-by: shrinivasan ganapathy <shrinivasanganapathy@gmail.com>
-rw-r--r--vcl-ldpreload/LICENSE202
-rw-r--r--vcl-ldpreload/MAINTAINERS30
-rw-r--r--vcl-ldpreload/README.md52
-rw-r--r--vcl-ldpreload/src/.gitignore11
-rw-r--r--vcl-ldpreload/src/Makefile.am62
-rw-r--r--vcl-ldpreload/src/configure.ac151
-rw-r--r--vcl-ldpreload/src/libvcl-ldpreload.am31
-rw-r--r--vcl-ldpreload/src/libvcl-ldpreload/TODO7
-rw-r--r--vcl-ldpreload/src/libvcl-ldpreload/vcom.c2611
-rw-r--r--vcl-ldpreload/src/libvcl-ldpreload/vcom.h163
-rw-r--r--vcl-ldpreload/src/libvcl-ldpreload/vcom_glibc_socket.h274
-rw-r--r--vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.c2000
-rw-r--r--vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.h213
-rw-r--r--vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.c772
-rw-r--r--vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.h205
-rw-r--r--vcl-ldpreload/src/vcl-ldpreload.mk9
16 files changed, 6792 insertions, 1 deletions
diff --git a/vcl-ldpreload/LICENSE b/vcl-ldpreload/LICENSE
new file mode 100644
index 0000000..7a4a3ea
--- /dev/null
+++ b/vcl-ldpreload/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License. \ No newline at end of file
diff --git a/vcl-ldpreload/MAINTAINERS b/vcl-ldpreload/MAINTAINERS
new file mode 100644
index 0000000..68c6204
--- /dev/null
+++ b/vcl-ldpreload/MAINTAINERS
@@ -0,0 +1,30 @@
+Descriptions of section entries:
+
+ M: Maintainer Full name and E-mail address: Full Name <address@domain>
+ One maintainer per line. Multiple M: lines acceptable.
+ F: Files and directories with wildcard patterns.
+ A trailing slash includes all files and subdirectory files.
+ F: drivers/net/ all files in and below drivers/net
+ F: drivers/net/* all files in drivers/net, but not below
+ One pattern per line. Multiple F: lines acceptable.
+ C: Single line comment related to current section.
+
+ -----------------------------------
+
+Build System
+M: Shrinivasan Ganapathy <shganapa@cisco.com>
+F: Makefile
+F: src/*.ac
+F: src/*.am
+F: src/*.mk
+F: src/m4/
+
+VCL-LDPRELOAD Library
+M: Shrinivasan Ganapathy <shganapa@cisco.com>
+F: src/libvcl-ldpreload/
+
+
+THE REST
+C: Contact vppsb-dev Mailing List <vppsb-dev@lists.fd.io>
+F: *
+F: */
diff --git a/vcl-ldpreload/README.md b/vcl-ldpreload/README.md
index 20dd49b..d1ec58a 100644
--- a/vcl-ldpreload/README.md
+++ b/vcl-ldpreload/README.md
@@ -1 +1,51 @@
-Stub
+# vcl-ldpreload a LD_PRELOAD library that uses VCL library for data transport
+
+libvcl_ldpreload.so library is to be used as a LD_PRELOAD library.
+User can LD_PRELOAD any application that uses POSIX socket API.
+This library internally uses libvppcom.so library from VPP project.
+
+
+## HowTo
+
+The library can be compiled by running the following commands from the vppsb/vcl-ldpreload/src directory:
+If VPP is installed, then
+```bash
+libtoolize
+aclocal
+autoconf
+automake
+./configure
+make
+sudo make install
+```
+If VPP is not installed, but rather built in a separate directory, you can use the VPP_DIR 'configure' argument.
+```bash
+autoreconf -i -f
+./configure VPP_DIR=<absolute/path/to/vpp>
+make
+sudo make install
+```bash
+
+Useful test script can be found in VPP project:
+.../vpp/test/scripts/socket_test.sh
+
+Running socket_test.sh without parameters will give the help menu.
+
+## Administrative
+
+### Current status
+
+This library is currently under active enhancement.
+
+### Objective
+
+This effort intends to be a building block for a better integration of POSIX socket applications with VPP.
+It will evolve depending on the needs of the VPP community while focusing on
+LD_PRELOADing applications that use POSIX socket APIs.
+
+### Main contributors
+
+Shrinivasan Ganapathy - LF-ID:shganapa
+
+
+
diff --git a/vcl-ldpreload/src/.gitignore b/vcl-ldpreload/src/.gitignore
new file mode 100644
index 0000000..e504a4d
--- /dev/null
+++ b/vcl-ldpreload/src/.gitignore
@@ -0,0 +1,11 @@
+aclocal.m4
+autom4te.cache
+compile
+config.guess
+config.sub
+configure
+depcomp
+install-sh
+ltmain.sh
+missing
+Makefile.in
diff --git a/vcl-ldpreload/src/Makefile.am b/vcl-ldpreload/src/Makefile.am
new file mode 100644
index 0000000..7f16e00
--- /dev/null
+++ b/vcl-ldpreload/src/Makefile.am
@@ -0,0 +1,62 @@
+# Copyright (c) 2016 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+###############################################################################
+# Global Defines
+###############################################################################
+
+AUTOMAKE_OPTIONS = foreign subdir-objects
+ACLOCAL_AMFLAGS = -I m4
+AM_LIBTOOLFLAGS = --quiet
+
+AM_CFLAGS = -Wall -fstack-protector -fPIC -Werror -g -DFORTIFY_SOURCE=2
+AM_LDFLAGS = -shared
+
+if VPP_DEBUG
+AM_CFLAGS += -O0 -DCLIB_DEBUG
+vpp_build = vpp_debug-native
+else
+AM_CFLAGS += -O2
+vpp_build = vpp-native
+endif
+
+if VCL_LDPRELOAD_DEBUG
+AM_CFLAGS += -ggdb '-DVCOM_DEBUG=1'
+else
+AM_CFLAGS += -Wall '-DVCOM_DEBUG=0'
+endif
+
+if VPP_DIR_SET
+vpp_install = @VPP_DIR@/build-root/install-$(vpp_build)
+AM_CFLAGS += -I$(vpp_install)/vpp/include/
+AM_LDFLAGS += -L$(vpp_install)/vpp/lib64/
+endif
+
+
+AM_LDFLAGS += -lvppcom -lvppinfra
+
+SUBDIRS = .
+noinst_HEADERS =
+dist_bin_SCRIPTS =
+lib_LTLIBRARIES =
+BUILT_SOURCES =
+CLEANFILES =
+
+
+###############################################################################
+# Components
+###############################################################################
+
+include libvcl-ldpreload.am
+
+
diff --git a/vcl-ldpreload/src/configure.ac b/vcl-ldpreload/src/configure.ac
new file mode 100644
index 0000000..cee7c95
--- /dev/null
+++ b/vcl-ldpreload/src/configure.ac
@@ -0,0 +1,151 @@
+AC_INIT([vcl-ldpreload], [1.0], [vpp-dev@fd.io])
+LT_INIT
+AC_CONFIG_AUX_DIR([.])
+AM_INIT_AUTOMAKE([subdir-objects])
+AM_SILENT_RULES([yes])
+AC_CONFIG_FILES([Makefile])
+AC_CONFIG_MACRO_DIR([m4])
+
+AC_PROG_CC
+AM_PROG_AS
+AM_PROG_LIBTOOL
+AC_PROG_YACC
+AM_PATH_PYTHON
+
+AC_ARG_VAR(VPP_DIR,[ vpp build directory ])
+AM_CONDITIONAL([VPP_DIR_SET], [test ! -z "$VPP_DIR"])
+
+###############################################################################
+# Macros
+###############################################################################
+
+AC_DEFUN([ENABLE_ARG],
+[
+ AC_ARG_ENABLE($1,
+ AC_HELP_STRING(patsubst([--enable-$1],[_],[-]), $2),
+ [enable_$1=yes n_enable_$1=1],
+ [enable_$1=no n_enable_$1=0])
+ AM_CONDITIONAL(m4_toupper(ENABLE_$1), test "$enable_$1" = "yes")
+ m4_append([list_of_enabled], [$1], [, ])
+])
+
+AC_DEFUN([DISABLE_ARG],
+[
+ AC_ARG_ENABLE($1,
+ AC_HELP_STRING(patsubst([--disable-$1],[_],[-]), $2),
+ [enable_$1=no n_enable_$1=0],
+ [enable_$1=yes n_enable_$1=1])
+ AM_CONDITIONAL(m4_toupper(ENABLE_$1), test "$enable_$1" = "yes")
+ m4_append([list_of_enabled], [$1], [, ])
+])
+
+AC_DEFUN([WITH_ARG],
+[
+ AC_ARG_WITH($1,
+ AC_HELP_STRING(patsubst([--with-$1],[_],[-]), $2),
+ [with_$1=yes n_with_$1=1],
+ [with_$1=no n_with_$1=0])
+ AM_CONDITIONAL(m4_toupper(WITH_$1), test "$with_$1" = "yes")
+ m4_append([list_of_with], [$1], [, ])
+])
+
+AC_DEFUN([WITHOUT_ARG],
+[
+ AC_ARG_WITH($1,
+ AC_HELP_STRING(patsubst([--without-$1],[_],[-]), $2),
+ [with_$1=no n_with_$1=0],
+ [with_$1=yes n_with_$1=1])
+ AM_CONDITIONAL(m4_toupper(WITH_$1), test "$with_$1" = "yes")
+ m4_append([list_of_with], [$1], [, ])
+])
+
+
+AC_DEFUN([PRINT_VAL], [ AC_MSG_RESULT(AC_HELP_STRING($1,$2)) ])
+
+
+###############################################################################
+# configure arguments
+###############################################################################
+
+# --enable-X
+
+AC_ARG_ENABLE([vpp-debug],
+[ --enable-vpp-debug Use vpp debug native build libraries],
+ [if test x$enableval = xyes; then
+ AC_DEFINE(VPP_DEBUG, 1, [Define this to use vpp debug native build libraries.])
+ vpp_debug=true
+ fi], [vpp_debug=false])
+AM_CONDITIONAL([VPP_DEBUG], [test x$vpp_debug = xtrue])
+
+AC_ARG_ENABLE([vcl-ldpreload-debug],
+[ --enable-vcl-ldpreload-debug Turn on vcl-ldpreload debugging],
+ [if test x$enableval = xyes; then
+ AC_DEFINE(VCL_LDPRELOAD_DEBUG, 1, [Define this to enable vcl-ldpreload debug.])
+ vcl_ldpreload_debug=true
+ fi], [vcl_ldpreload_debug=false])
+AM_CONDITIONAL([VCL_LDPRELOAD_DEBUG], [test x$vcl_ldpreload_debug = xtrue])
+
+# --disable-X
+
+# --with-X
+
+# --without-X
+
+AC_ARG_WITH(unix,
+ AC_HELP_STRING([--with-unix],[Compile unix version of clib]),
+ [],
+ [case $host_os in
+ darwin* | linux*) with_unix=yes;;
+ *) with_unix=no;;
+ esac])
+
+AM_CONDITIONAL(WITH_UNIX, test "$with_unix" = "yes")
+
+
+###############################################################################
+# Substitutions and defines
+###############################################################################
+
+
+# Silence following noise:
+# ar: `u' modifier ignored since `D' is the default (see `U')
+AR_FLAGS=cr
+AC_SUBST(AR_FLAGS)
+
+
+###############################################################################
+# Dependency checks
+###############################################################################
+
+###############################################################################
+# Output
+###############################################################################
+
+AC_OUTPUT
+
+AC_MSG_RESULT([==============================================================================])
+PRINT_VAL([version], $PACKAGE $VERSION)
+PRINT_VAL([prefix], ${prefix})
+PRINT_VAL([exec_prefix], ${exec_prefix})
+PRINT_VAL([libdir], ${libdir})
+PRINT_VAL([includedir], ${includedir})
+PRINT_VAL([CFLAGS], ${CFLAGS})
+PRINT_VAL([CPPFLAGS], ${CPPFLAGS})
+PRINT_VAL([LDFLAGS], ${LDFLAGS})
+
+AC_MSG_RESULT([])
+AC_MSG_RESULT([with:])
+m4_foreach([x], m4_dquote(list_of_with), [
+ AC_MSG_RESULT(AC_HELP_STRING(x, m4_join([], [${with_], x, [}])))
+])
+
+AC_MSG_RESULT([])
+AC_MSG_RESULT([enabled:])
+m4_foreach([x], m4_dquote(list_of_enabled), [
+ AC_MSG_RESULT(AC_HELP_STRING(x, m4_join([], [${enable_], x, [}])))
+])
+
+AC_MSG_RESULT([])
+AC_MSG_RESULT([==============================================================================])
+
+
diff --git a/vcl-ldpreload/src/libvcl-ldpreload.am b/vcl-ldpreload/src/libvcl-ldpreload.am
new file mode 100644
index 0000000..0d2fcb5
--- /dev/null
+++ b/vcl-ldpreload/src/libvcl-ldpreload.am
@@ -0,0 +1,31 @@
+# Copyright (c) 2016 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+lib_LTLIBRARIES += libvcl_ldpreload.la
+
+libvcl_ldpreload_la_SOURCES =
+nobase_include_HEADERS =
+
+libvcl_ldpreload_la_LIBADD = -lvppinfra -lvppcom -lpthread
+
+libvcl_ldpreload_la_SOURCES += \
+ libvcl-ldpreload/vcom_socket_wrapper.c \
+ libvcl-ldpreload/vcom.c \
+ libvcl-ldpreload/vcom_socket.c
+
+nobase_include_HEADERS += \
+ libvcl-ldpreload/vcom_socket_wrapper.h \
+ libvcl-ldpreload/vcom_glibc_socket.h \
+ libvcl-ldpreload/vcom.h \
+ libvcl-ldpreload/vcom_socket.h
+
diff --git a/vcl-ldpreload/src/libvcl-ldpreload/TODO b/vcl-ldpreload/src/libvcl-ldpreload/TODO
new file mode 100644
index 0000000..63ec21e
--- /dev/null
+++ b/vcl-ldpreload/src/libvcl-ldpreload/TODO
@@ -0,0 +1,7 @@
+VCL-LDPRELOAD Library project plan.
+
+1. [shganapa] LD_PRELOAD iperf3 application.
+
+
+NOTES:
+1. Not all POSIX socket API's are LD_PRELOADED.
diff --git a/vcl-ldpreload/src/libvcl-ldpreload/vcom.c b/vcl-ldpreload/src/libvcl-ldpreload/vcom.c
new file mode 100644
index 0000000..cbd9729
--- /dev/null
+++ b/vcl-ldpreload/src/libvcl-ldpreload/vcom.c
@@ -0,0 +1,2611 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <unistd.h>
+#include <stdio.h>
+#include <signal.h>
+#include <dlfcn.h>
+#include <pthread.h>
+#include <time.h>
+
+#include <stdarg.h>
+
+#include <svm/svm_fifo_segment.h>
+#include <vlibmemory/api.h>
+#include <vpp/api/vpe_msg_enum.h>
+#include <vnet/session/application_interface.h>
+
+#define vl_typedefs /* define message structures */
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_typedefs
+
+/* declare message handlers for each api */
+
+#define vl_endianfun /* define message structures */
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_endianfun
+
+/* instantiate all the print functions we know about */
+#define vl_print(handle, ...)
+#define vl_printfun
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_printfun
+
+#include <libvcl-ldpreload/vcom_socket_wrapper.h>
+#include <libvcl-ldpreload/vcom.h>
+#include <sys/time.h>
+
+#include <uri/vppcom.h>
+#include <libvcl-ldpreload/vcom_socket.h>
+
+
+
+/* GCC have printf type attribute check. */
+#ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
+#define PRINTF_ATTRIBUTE(a,b) \
+ __attribute__ ((__format__ (__printf__, a, b)))
+#else
+#define PRINTF_ATTRIBUTE(a,b)
+#endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
+
+#define HAVE_CONSTRUCTOR_ATTRIBUTE
+#ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
+#define CONSTRUCTOR_ATTRIBUTE \
+ __attribute__ ((constructor))
+#else
+#define CONSTRUCTOR_ATTRIBUTE
+#endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
+
+#define HAVE_DESTRUCTOR_ATTRIBUTE
+#ifdef HAVE_DESTRUCTOR_ATTRIBUTE
+#define DESTRUCTOR_ATTRIBUTE \
+ __attribute__ ((destructor))
+#else
+#define DESTRUCTOR_ATTRIBUTE
+#endif
+
+#define HAVE_ADDRESS_SANITIZER_ATTRIBUTE
+#ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
+#define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE \
+ __attribute__((no_sanitize_address))
+#else
+#define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
+#endif
+
+
+
+
+
+
+#define VCOM_SOCKET_FD_MAX 0x10000
+
+static char vcom_app_name[MAX_VCOM_APP_NAME];
+
+/*
+ * RETURN: 0 on success or -1 on error.
+ * */
+int
+vcom_set_app_name (char *__app_name)
+{
+ return snprintf (vcom_app_name, MAX_VCOM_APP_NAME, "vcom-%s-%d",
+ __app_name, getpid ()) < 0 ? -1 : 0;
+}
+
+static char *
+vcom_get_app_name ()
+{
+ if (vcom_app_name[0] == '\0')
+ {
+ snprintf (vcom_app_name, MAX_VCOM_APP_NAME, "vcom-app-%d", getpid ());
+ }
+ return vcom_app_name;
+}
+
+/*
+ * 1 if init, 0 otherwise
+ */
+static int is_vcom_init;
+
+/*
+ * TBD: Make it thread safe
+ */
+
+/*
+ * constructor function called before main is called
+ * RETURN: 0 on success -1 on failure
+ * */
+static inline int
+vcom_init ()
+{
+ pid_t pid = getpid ();
+
+ if (!is_vcom_init)
+ {
+ if (vppcom_app_create (vcom_get_app_name ()) != 0)
+ {
+ printf ("\n[%d] vcom_init...failed!\n", pid);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] vcom_init: vppcom_app_create failed!\n", pid);
+ return -1;
+ }
+ if (vcom_socket_main_init () != 0)
+ {
+ printf ("\n[%d] vcom_init...failed!\n", pid);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] vcom_init: vcom_socket_main_init failed!\n", pid);
+ return -1;
+ }
+
+ is_vcom_init = 1;
+ printf ("\n[%d] vcom_init...done!\n", pid);
+ }
+ return 0;
+}
+
+static inline void
+vcom_destroy (void)
+{
+ pid_t pid = getpid ();
+
+ if (is_vcom_init)
+ {
+ vcom_socket_main_destroy ();
+ vppcom_app_destroy ();
+ is_vcom_init = 0;
+ fprintf (stderr, "\n[%d] vcom_destroy...done!\n", pid);
+ }
+}
+
+static inline int
+is_vcom_socket_fd (int fd)
+{
+ return vcom_socket_is_vcom_fd (fd);
+}
+
+/*
+ *
+ * Generic glibc fd api
+ *
+ */
+
+/* Close the file descriptor FD.
+
+ This function is a cancellation point and therefore
+ not marked with __THROW. */
+/*
+ * PRE: is_vcom_socket_fd(__fd) == 1
+ * RETURN: 0 on success and -1 for errors.
+ * */
+int
+vcom_close (int __fd)
+{
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ if (vcom_socket_close (__fd) != 0)
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * RETURN: 0 on success, or -1 on error
+ */
+int
+close (int __fd)
+{
+ int rv;
+ pid_t pid = getpid ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ if (VCOM_DEBUG > 0)
+ vcom_socket_main_show ();
+ rv = vcom_close (__fd);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr, "[%d] close: " "'%04d'='%04d'\n", pid, rv, __fd);
+ if (VCOM_DEBUG > 0)
+ vcom_socket_main_show ();
+ if (rv != 0)
+ {
+ errno = -rv;
+ return -1;
+ }
+ return 0;
+ }
+ return libc_close (__fd);
+}
+
+/* Read NBYTES into BUF from FD. Return the
+ number read, -1 for errors or 0 for EOF.
+
+ This function is a cancellation point and therefore
+ not marked with __THROW. */
+ssize_t
+vcom_read (int __fd, void *__buf, size_t __nbytes)
+{
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ return vcom_socket_read (__fd, __buf, __nbytes);
+}
+
+ssize_t
+read (int __fd, void *__buf, size_t __nbytes)
+{
+ ssize_t size = 0;
+ pid_t pid = getpid ();
+ pthread_t tid = pthread_self ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d][%lu (0x%lx)] read:1 "
+ "'%04d'='%04d', '%p', '%04d'\n",
+ pid, (unsigned long) tid, (unsigned long) tid,
+ (int) size, __fd, __buf, (int) __nbytes);
+ size = vcom_read (__fd, __buf, __nbytes);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d][%lu (0x%lx)] read:2 "
+ "'%04d'='%04d', '%p', '%04d'\n",
+ pid, (unsigned long) tid, (unsigned long) tid,
+ (int) size, __fd, __buf, (int) __nbytes);
+ if (size < 0)
+ {
+ errno = -size;
+ return -1;
+ }
+ return size;
+ }
+ return libc_read (__fd, __buf, __nbytes);
+}
+
+/* Write N bytes of BUF to FD. Return the number written, or -1.
+
+ This function is a cancellation point and therefore
+ not marked with __THROW. */
+ssize_t
+vcom_write (int __fd, const void *__buf, size_t __n)
+{
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ return vcom_socket_write (__fd, (void *) __buf, __n);
+}
+
+ssize_t
+write (int __fd, const void *__buf, size_t __n)
+{
+ ssize_t size = 0;
+ pid_t pid = getpid ();
+ pthread_t tid = pthread_self ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d][%lu (0x%lx)] write:1 "
+ "'%04d'='%04d', '%p', '%04d'\n",
+ pid, (unsigned long) tid, (unsigned long) tid,
+ (int) size, __fd, __buf, (int) __n);
+ size = vcom_write (__fd, __buf, __n);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d][%lu (0x%lx)] write:2 "
+ "'%04d'='%04d', '%p', '%04d'\n",
+ pid, (unsigned long) tid, (unsigned long) tid,
+ (int) size, __fd, __buf, (int) __n);
+ if (size < 0)
+ {
+ errno = -size;
+ return -1;
+ }
+ return size;
+ }
+ return libc_write (__fd, __buf, __n);
+}
+
+/* Do the file control operation described by CMD on FD.
+ The remaining arguments are interpreted depending on CMD.
+
+ This function is a cancellation point and therefore
+ not marked with __THROW. */
+int
+vcom_fcntl_va (int __fd, int __cmd, va_list __ap)
+{
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ return vcom_socket_fcntl_va (__fd, __cmd, __ap);
+}
+
+int
+vcom_fcntl (int __fd, int __cmd, ...)
+{
+ int rv = -1;
+ va_list ap;
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ va_start (ap, __cmd);
+ rv = vcom_fcntl_va (__fd, __cmd, ap);
+ va_end (ap);
+ }
+ return rv;
+}
+
+int
+fcntl (int __fd, int __cmd, ...)
+{
+ int rv;
+ va_list ap;
+ pid_t pid = getpid ();
+
+ va_start (ap, __cmd);
+ if (is_vcom_socket_fd (__fd))
+ {
+ rv = vcom_fcntl_va (__fd, __cmd, ap);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] fcntl: "
+ "'%04d'='%04d', '%04d'\n", pid, rv, __fd, __cmd);
+ if (rv < 0)
+ {
+ errno = -rv;
+ rv = -1;
+ }
+ goto out;
+ }
+ rv = libc_vfcntl (__fd, __cmd, ap);
+
+out:
+ va_end (ap);
+ return rv;
+}
+
+/*
+ * Check the first NFDS descriptors each in READFDS (if not NULL) for
+ * read readiness, in WRITEFDS (if not NULL) for write readiness,
+ * and in EXCEPTFDS (if not NULL) for exceptional conditions.
+ * If TIMEOUT is not NULL, time out after waiting the interval
+ * specified therein. Returns the number of ready descriptors,
+ * or -1 for errors.
+ *
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+
+/*
+ * clear all vcom FDs from fd_sets __readfds, __writefds and
+ * __exceptfds and update the new nfds
+ *
+ * new nfds is the highest-numbered file descriptor
+ * in any of the three sets, plus 1
+ *
+ * Return the number of file descriptors contained in the
+ * three descriptor sets. ie. the total number of the bits
+ * that are set in __readfds, __writefds and __exceptfds
+ */
+static inline int
+vcom_fd_clear (int __nfds,
+ int *__new_nfds,
+ fd_set * __restrict __readfds,
+ fd_set * __restrict __writefds,
+ fd_set * __restrict __exceptfds)
+{
+ int fd;
+ /* invalid max_fd is -1 */
+ int max_fd = -1;
+ int nfd = 0;
+
+
+ /* clear all vcom fd from the sets */
+ for (fd = 0; fd < __nfds; fd++)
+ {
+
+ /* clear vcom fd from set */
+ /*
+ * F fd set
+ */
+#define _(F) \
+ if ((F) && FD_ISSET (fd, (F))) \
+ { \
+ if (is_vcom_socket_fd (fd)) \
+ { \
+ FD_CLR (fd, (F)); \
+ } \
+ }
+
+
+ _(__readfds);
+ _(__writefds);
+ _(__exceptfds);
+#undef _
+ }
+
+ /*
+ * compute nfd and __new_nfds
+ */
+ for (fd = 0; fd < __nfds; fd++)
+ {
+
+ /*
+ * F fd set
+ */
+#define _(F) \
+ if ((F) && FD_ISSET (fd, (F))) \
+ { \
+ if (fd > max_fd) \
+ { \
+ max_fd = fd; \
+ } \
+ ++nfd; \
+ }
+
+
+ _(__readfds);
+ _(__writefds);
+ _(__exceptfds);
+#undef _
+ }
+
+ *__new_nfds = max_fd != -1 ? max_fd + 1 : 0;
+ return nfd;
+}
+
+/*
+ * Return the number of file descriptors contained in the
+ * three descriptor sets. ie. the total number of the bits
+ * that are set in __readfds, __writefds and __exceptfds
+ */
+static inline int
+vcom_fd_set (int __nfds,
+ /* dest */
+ int *__new_nfds,
+ fd_set * __restrict __readfds,
+ fd_set * __restrict __writefds, fd_set * __restrict __exceptfds,
+ /* src */
+ fd_set * __restrict __saved_readfds,
+ fd_set * __restrict __saved_writefds,
+ fd_set * __restrict __saved_exceptfds)
+{
+ int fd;
+ /* invalid max_fd is -1 */
+ int max_fd = -1;
+ int nfd = 0;
+
+ for (fd = 0; fd < __nfds; fd++)
+ {
+ /*
+ * F fd set
+ * S saved fd set
+ */
+#define _(S,F) \
+ if ((F) && (S) && FD_ISSET (fd, (S))) \
+ { \
+ if (is_vcom_socket_fd (fd)) \
+ { \
+ FD_SET (fd, (F)); \
+ } \
+ }
+
+
+ _(__saved_readfds, __readfds);
+ _(__saved_writefds, __writefds);
+#undef _
+ }
+
+
+ /*
+ * compute nfd and __new_nfds
+ */
+ for (fd = 0; fd < __nfds; fd++)
+ {
+
+ /*
+ * F fd set
+ */
+#define _(F) \
+ if ((F) && FD_ISSET (fd, (F))) \
+ { \
+ if (fd > max_fd) \
+ { \
+ max_fd = fd; \
+ } \
+ ++nfd; \
+ }
+
+
+ _(__readfds);
+ _(__writefds);
+ _(__exceptfds);
+#undef _
+ }
+
+ *__new_nfds = max_fd != -1 ? max_fd + 1 : 0;
+ return nfd;
+}
+
+/*
+ * split select sets(src) into
+ * vcom sets(dest1) and libc sets(dest2)
+ */
+static inline void
+vcom_fd_set_split (
+ /* src, select sets */
+ int nfds,
+ fd_set * __restrict readfds,
+ fd_set * __restrict writefds,
+ fd_set * __restrict exceptfds,
+ /* dest1, vcom sets */
+ int *vcom_nfds,
+ fd_set * __restrict vcom_readfds,
+ fd_set * __restrict vcom_writefds,
+ fd_set * __restrict vcom_exceptfds, int *vcom_nfd,
+ /* dest2, libc sets */
+ int *libc_nfds,
+ fd_set * __restrict libc_readfds,
+ fd_set * __restrict libc_writefds,
+ fd_set * __restrict libc_exceptfds, int *libc_nfd)
+{
+ int fd;
+
+ /* vcom */
+ /* invalid max_fd is -1 */
+ int vcom_max_fd = -1;
+ int vcom_nfd2 = 0;
+
+ /* libc */
+ /* invalid max_fd is -1 */
+ int libc_max_fd = -1;
+ int libc_nfd2 = 0;
+
+
+ for (fd = 0; fd < nfds; fd++)
+ {
+ /*
+ * S select fd set
+ * V vcom fd set
+ * L libc fd set
+ */
+#define _(S,V,L) \
+ if ((S) && FD_ISSET (fd, (S))) \
+ { \
+ if (is_vcom_socket_fd (fd)) \
+ { \
+ if ((V)) \
+ { \
+ FD_SET(fd, (V)); \
+ if (fd > vcom_max_fd) \
+ { \
+ vcom_max_fd = fd; \
+ } \
+ ++vcom_nfd2; \
+ } \
+ } \
+ else \
+ { \
+ if ((L)) \
+ { \
+ FD_SET(fd, (L)); \
+ if (fd > libc_max_fd) \
+ { \
+ libc_max_fd = fd; \
+ } \
+ ++libc_nfd2; \
+ } \
+ } \
+ }
+
+
+ _(readfds, vcom_readfds, libc_readfds);
+ _(writefds, vcom_writefds, libc_writefds);
+ _(exceptfds, vcom_exceptfds, libc_exceptfds);
+#undef _
+ }
+
+ if (vcom_nfds)
+ *vcom_nfds = vcom_max_fd != -1 ? vcom_max_fd + 1 : 0;
+ if (vcom_nfd)
+ *vcom_nfd = vcom_nfd2;
+ if (libc_nfds)
+ *libc_nfds = libc_max_fd != -1 ? libc_max_fd + 1 : 0;
+ if (libc_nfd)
+ *libc_nfd = libc_nfd2;
+}
+
+/*
+ * merge vcom sets(src1) and libc sets(src2)
+ * into select sets(dest)
+ */
+static inline void
+vcom_fd_set_merge (
+ /* dest, select sets */
+ int *nfds,
+ fd_set * __restrict readfds,
+ fd_set * __restrict writefds,
+ fd_set * __restrict exceptfds, int *nfd,
+ /* src1, vcom sets */
+ int vcom_nfds,
+ fd_set * __restrict vcom_readfds,
+ fd_set * __restrict vcom_writefds,
+ fd_set * __restrict vcom_exceptfds, int vcom_nfd,
+ /* src2, libc sets */
+ int libc_nfds,
+ fd_set * __restrict libc_readfds,
+ fd_set * __restrict libc_writefds,
+ fd_set * __restrict libc_exceptfds, int libc_nfd)
+{
+ int fd;
+ /* invalid max_fd is -1 */
+ int max_fd = -1;
+ int nfd2 = 0;
+
+
+ /* FD_BIT_OR
+ *
+ * dest |= src at current bit index
+ * update MAX and NFD of dest fd set
+ *
+ *
+ * FS source fd set
+ * FD dest fd set
+ * BI bit index
+ * MAX current max_fd of dest fd sets
+ * NFD current nfd of dest fd sets
+ * N nfds of source fd set
+ */
+#define FD_BIT_OR(FD,FS,BI, \
+ MAX,NFD) \
+ if ((FS) && (FD) && FD_ISSET ((BI), (FS))) \
+ { \
+ FD_SET ((BI), (FD)); \
+ if ((BI) > (MAX)) \
+ { \
+ (MAX) = (BI); \
+ } \
+ ++(NFD); \
+ }
+
+
+ /* FD_RWE_SET_OR */
+ /*
+ * SR,SW,SE source RWE fd sets
+ * DR,DW,DE dest RWE fd sets
+ * BI bit index
+ * NFDS nfds of source fd sets
+ * MAX current max_fd of dest fd sets
+ * NFD current nfd of dest fd sets
+ */
+#define FD_RWE_SETS_OR(DR,DW,DE, \
+ SR,SW,SE, \
+ BI,NFDS, \
+ MAX,NFD) \
+ do \
+ { \
+ for ((BI) = 0; (BI) < (NFDS); (BI)++) \
+ { \
+ FD_BIT_OR((DR), (SR), (BI), (MAX), (NFD)); \
+ FD_BIT_OR((DW), (SW), (BI), (MAX), (NFD)); \
+ FD_BIT_OR((DE), (SE), (BI), (MAX), (NFD)); \
+ } \
+ } \
+ while (0);
+
+
+ /* source(vcom) to dest(select) rwe fd sets */
+ FD_RWE_SETS_OR (readfds, writefds, exceptfds,
+ vcom_readfds, vcom_writefds, vcom_exceptfds,
+ fd, vcom_nfds, max_fd, nfd2);
+
+ /* source(libc) to dest(select) rwe fd sets */
+ FD_RWE_SETS_OR (readfds, writefds, exceptfds,
+ libc_readfds, libc_writefds, libc_exceptfds,
+ fd, libc_nfds, max_fd, nfd2);
+
+#undef FD_RWE_SETS_OR
+#undef FD_BIT_OR
+
+ if (nfds)
+ *nfds = max_fd != -1 ? max_fd + 1 : 0;
+ if (nfd)
+ *nfd = nfd2;
+}
+
+/*
+ * RETURN 1 if fds is NULL or empty. 0 otherwise
+ */
+static inline int
+fd_set_iszero (fd_set * __restrict fds)
+{
+ int fd;
+
+ /* NULL fds */
+ if (!fds)
+ return 1;
+
+ for (fd = 0; fd < FD_SETSIZE; fd++)
+ {
+ if (FD_ISSET (fd, fds))
+ {
+ /* non-empty fds */
+ return 0;
+ }
+ }
+ /* empty fds */
+ return 1;
+}
+
+
+/*
+ * ################
+ * kernel time64.h
+ * ################
+ * */
+typedef long int s64;
+typedef unsigned long int u64;
+
+typedef long long int __s64;
+typedef unsigned long long int __u64;
+
+typedef __s64 time64_t;
+typedef __u64 timeu64_t;
+
+/* Parameters used to convert the timespec values: */
+#define MSEC_PER_SEC 1000L
+#define USEC_PER_MSEC 1000L
+#define NSEC_PER_USEC 1000L
+#define NSEC_PER_MSEC 1000000L
+#define USEC_PER_SEC 1000000L
+#define NSEC_PER_SEC 1000000000L
+#define FSEC_PER_SEC 1000000000000000LL
+
+
+/*
+ * ################
+ * kernel time.h
+ * ################
+ * */
+
+
+#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
+
+static inline int
+timespec_equal (const struct timespec *a, const struct timespec *b)
+{
+ return (a->tv_sec == b->tv_sec) && (a->tv_nsec == b->tv_nsec);
+}
+
+/*
+ * lhs < rhs: return <0
+ * lhs == rhs: return 0
+ * lhs > rhs: return >0
+ */
+static inline int
+timespec_compare (const struct timespec *lhs, const struct timespec *rhs)
+{
+ if (lhs->tv_sec < rhs->tv_sec)
+ return -1;
+ if (lhs->tv_sec > rhs->tv_sec)
+ return 1;
+ return lhs->tv_nsec - rhs->tv_nsec;
+}
+
+static inline int
+timeval_compare (const struct timeval *lhs, const struct timeval *rhs)
+{
+ if (lhs->tv_sec < rhs->tv_sec)
+ return -1;
+ if (lhs->tv_sec > rhs->tv_sec)
+ return 1;
+ return lhs->tv_usec - rhs->tv_usec;
+}
+
+extern void set_normalized_timespec (struct timespec *ts, time_t sec,
+ s64 nsec);
+
+
+static inline struct timespec
+timespec_add (struct timespec lhs, struct timespec rhs)
+{
+ struct timespec ts_delta;
+ set_normalized_timespec (&ts_delta, lhs.tv_sec + rhs.tv_sec,
+ lhs.tv_nsec + rhs.tv_nsec);
+ return ts_delta;
+}
+
+/*
+ * sub = lhs - rhs, in normalized form
+ */
+static inline struct timespec
+timespec_sub (struct timespec lhs, struct timespec rhs)
+{
+ struct timespec ts_delta;
+ set_normalized_timespec (&ts_delta, lhs.tv_sec - rhs.tv_sec,
+ lhs.tv_nsec - rhs.tv_nsec);
+ return ts_delta;
+}
+
+/*
+ * ################
+ * kernel time.c
+ * ################
+ * */
+
+
+/**
+ * set_normalized_timespec - set timespec sec and nsec parts and normalize
+ *
+ * @ts: pointer to timespec variable to be set
+ * @sec: seconds to set
+ * @nsec: nanoseconds to set
+ *
+ * Set seconds and nanoseconds field of a timespec variable and
+ * normalize to the timespec storage format
+ *
+ * Note: The tv_nsec part is always in the range of
+ * 0 <= tv_nsec < NSEC_PER_SEC
+ * For negative values only the tv_sec field is negative !
+ */
+void
+set_normalized_timespec (struct timespec *ts, time_t sec, s64 nsec)
+{
+ while (nsec >= NSEC_PER_SEC)
+ {
+ /*
+ * The following asm() prevents the compiler from
+ * optimising this loop into a modulo operation. See
+ * also __iter_div_u64_rem() in include/linux/time.h
+ */
+ asm ("":"+rm" (nsec));
+ nsec -= NSEC_PER_SEC;
+ ++sec;
+ }
+ while (nsec < 0)
+ {
+ asm ("":"+rm" (nsec));
+ nsec += NSEC_PER_SEC;
+ --sec;
+ }
+ ts->tv_sec = sec;
+ ts->tv_nsec = nsec;
+}
+
+#define vcom_timerisvalid(tvp) (!((tvp)->tv_sec < 0 || (tvp)->tv_usec < 0))
+
+/* Macros for converting between `struct timeval' and `struct timespec'. */
+#define VCOM_TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+#define VCOM_TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+}
+
+static inline int
+vcom_select_impl (int vcom_nfds, fd_set * __restrict vcom_readfds,
+ fd_set * __restrict vcom_writefds,
+ fd_set * __restrict vcom_exceptfds,
+ struct timeval *__restrict timeout)
+{
+ return vcom_socket_select (vcom_nfds, vcom_readfds,
+ vcom_writefds, vcom_exceptfds, timeout);
+}
+
+int
+vcom_select (int __nfds, fd_set * __restrict __readfds,
+ fd_set * __restrict __writefds,
+ fd_set * __restrict __exceptfds,
+ struct timeval *__restrict __timeout)
+{
+ int rv;
+ int rv2 = 0;
+ pid_t pid = getpid ();
+
+ int timedout = 0;
+ /* block indefinitely */
+ int no_timeout = 0;
+ int first_clock_gettime_failed = 0;
+ /* timeout value in units of timespec */
+ struct timespec timeout_ts;
+ struct timespec start_time, now, end_time;
+
+ /* select sets attributes - after merge */
+ int new_nfds = 0;
+ int new_nfd = -1;
+
+ /* vcom */
+ int vcom_nfds = 0;
+ fd_set vcom_readfds;
+ fd_set vcom_writefds;
+ fd_set vcom_exceptfds;
+ int vcom_nfd = -1;
+
+ /* libc */
+ int libc_nfds = 0;
+ fd_set libc_readfds;
+ fd_set libc_writefds;
+ fd_set libc_exceptfds;
+ int libc_nfd = -1;
+
+ /* for polling */
+ struct timeval tv = {.tv_sec = 0,.tv_usec = 0 };
+
+ /* validate __timeout */
+ if (__timeout)
+ {
+ /* validate tv_sec */
+ /* bogus */
+ if (!vcom_timerisvalid (__timeout))
+ {
+ rv = -EINVAL;
+ goto select_done;
+ }
+
+ /* validate tv_usec */
+ /* TBD: */
+ /* init timeout_ts */
+ VCOM_TIMEVAL_TO_TIMESPEC (__timeout, &timeout_ts);
+ set_normalized_timespec (&timeout_ts,
+ timeout_ts.tv_sec, timeout_ts.tv_nsec);
+ }
+
+ rv = clock_gettime (CLOCK_MONOTONIC, &start_time);
+ if (rv == -1)
+ {
+ rv = -errno;
+ first_clock_gettime_failed = 1;
+ goto select_done;
+ }
+
+ /* init end_time */
+ if (__timeout)
+ {
+ if (timerisset (__timeout))
+ {
+ end_time = timespec_add (start_time, timeout_ts);
+ }
+ else
+ {
+ /*
+ * if both fields of the timeout structure are zero,
+ * then select returns immediately
+ * */
+ end_time = start_time;
+ }
+ }
+ else
+ {
+ /* block indefinitely */
+ no_timeout = 1;
+ }
+
+
+
+ if (vcom_init () != 0)
+ {
+ rv = -1;
+ goto select_done;
+ }
+
+ /* validate __nfds */
+ if (__nfds < 0 || __nfds > FD_SETSIZE)
+ {
+ rv = -EINVAL;
+ goto select_done;
+ }
+
+
+ /*
+ * usleep(3) emulation
+ * */
+
+ /* call libc_select() with a finite timeout and
+ * no file descriptors or empty fd sets and
+ * zero nfds */
+ if (__nfds == 0 &&
+ (!__readfds || fd_set_iszero (__readfds)) &&
+ (!__writefds || fd_set_iszero (__writefds)) &&
+ (!__exceptfds || fd_set_iszero (__exceptfds)))
+ {
+ if (__timeout)
+ {
+ rv = libc_select (__nfds,
+ __readfds, __writefds, __exceptfds, __timeout);
+ if (rv == -1)
+ rv = -errno;
+ }
+ else
+ {
+ /* TBD: block indefinitely or return -EINVAL */
+ rv = -EINVAL;
+ }
+ goto select_done;
+ }
+
+ /* init once before the polling loop */
+
+ /* zero vcom and libc fd sets */
+ /*
+ * S select fd set
+ * V vcom fd set
+ * L libc fd set
+ */
+#define _(S,V,L) \
+ if ((S)) \
+ { \
+ FD_ZERO ((V)); \
+ FD_ZERO ((L)); \
+ }
+
+
+ _(__readfds, &vcom_readfds, &libc_readfds);
+ _(__writefds, &vcom_writefds, &libc_writefds);
+ _(__exceptfds, &vcom_exceptfds, &libc_exceptfds);
+#undef _
+ new_nfds = 0;
+ new_nfd = -1;
+
+ vcom_nfds = 0;
+ vcom_nfd = -1;
+ libc_nfds = 0;
+ libc_nfd = -1;
+
+ vcom_fd_set_split (
+ /* src, select sets */
+ __nfds, __readfds, __writefds, __exceptfds,
+ /* dest1, vcom sets */
+ __readfds || __writefds || __exceptfds ?
+ &vcom_nfds : NULL,
+ __readfds ? &vcom_readfds : NULL,
+ __writefds ? &vcom_writefds : NULL,
+ __exceptfds ? &vcom_exceptfds : NULL,
+ __readfds || __writefds || __exceptfds ?
+ &vcom_nfd : NULL,
+ /* dest2, libc sets */
+ __readfds || __writefds || __exceptfds ?
+ &libc_nfds : NULL,
+ __readfds ? &libc_readfds : NULL,
+ __writefds ? &libc_writefds : NULL,
+ __exceptfds ? &libc_exceptfds : NULL,
+ __readfds || __writefds || __exceptfds ?
+ &libc_nfd : NULL);
+
+ /*
+ * polling loop
+ * */
+ do
+ {
+ new_nfd = -1;
+ vcom_nfd = -1;
+ libc_nfd = -1;
+
+ /*
+ * if both fields of timeval structure are zero,
+ * vcom_select_impl and libc_select returns immediately.
+ * useful for polling and ensure fairness among
+ * file descriptors watched.
+ */
+
+ /* for polling */
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+
+ /* select on vcom fds */
+ if (vcom_nfds)
+ {
+ vcom_nfd = vcom_select_impl (vcom_nfds,
+ __readfds ? &vcom_readfds : NULL,
+ __writefds ? &vcom_writefds : NULL,
+ __exceptfds ? &vcom_exceptfds : NULL,
+ &tv);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] select vcom: "
+ "'%04d'='%04d'\n", pid, vcom_nfd, vcom_nfds);
+
+ if (vcom_nfd < 0)
+ {
+ rv = vcom_nfd;
+ goto select_done;
+ }
+ }
+ /* select on libc fds */
+ if (libc_nfds)
+ {
+ libc_nfd = libc_select (libc_nfds,
+ __readfds ? &libc_readfds : NULL,
+ __writefds ? &libc_writefds : NULL,
+ __exceptfds ? &libc_exceptfds : NULL, &tv);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] select libc: "
+ "'%04d'='%04d'\n", pid, libc_nfd, libc_nfds);
+
+ if (libc_nfd < 0)
+ {
+ /* tv becomes undefined */
+ libc_nfd = errno;
+ rv = libc_nfd;
+ goto select_done;
+ }
+ }
+
+ /* check if any file descriptors changed status */
+ if ((vcom_nfds && vcom_nfd > 0) || (libc_nfds && libc_nfd > 0))
+ {
+ /* zero the sets before merge and exit */
+
+ /*
+ * F fd set
+ */
+#define _(F) \
+ if ((F)) \
+ { \
+ FD_ZERO ((F)); \
+ }
+
+
+ _(__readfds);
+ _(__writefds);
+ _(__exceptfds);
+#undef _
+ new_nfds = 0;
+ new_nfd = -1;
+
+ /*
+ * on exit, sets are modified in place to indicate which
+ * file descriptors actually changed status
+ * */
+ vcom_fd_set_merge (
+ /* dest, select sets */
+ __readfds || __writefds || __exceptfds ?
+ &new_nfds : NULL,
+ __readfds,
+ __writefds,
+ __exceptfds,
+ __readfds || __writefds || __exceptfds ?
+ &new_nfd : NULL,
+ /* src1, vcom sets */
+ vcom_nfds,
+ __readfds ? &vcom_readfds : NULL,
+ __writefds ? &vcom_writefds : NULL,
+ __exceptfds ? &vcom_exceptfds : NULL, vcom_nfd,
+ /* src2, libc sets */
+ libc_nfds,
+ __readfds ? &libc_readfds : NULL,
+ __writefds ? &libc_writefds : NULL,
+ __exceptfds ? &libc_exceptfds : NULL, libc_nfd);
+ /*
+ * return the number of file descriptors contained in the
+ * three returned sets
+ * */
+ rv = 0;
+ /*
+ * for documentation
+ *
+ * if(vcom_nfd > 0)
+ * rv += vcom_nfd;
+ * if(libc_nfd > 0)
+ * rv += libc_nfd;
+ */
+
+ rv = new_nfd == -1 ? 0 : new_nfd;
+ goto select_done;
+ }
+
+ rv = clock_gettime (CLOCK_MONOTONIC, &now);
+ if (rv == -1)
+ {
+ rv = -errno;
+ goto select_done;
+ }
+ }
+ while (no_timeout || timespec_compare (&now, &end_time) < 0);
+
+ /* timeout expired before anything interesting happened */
+ timedout = 1;
+ rv = 0;
+
+select_done:
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr, "[%d] vselect1: " "'%04d'='%04d'\n", pid, rv, __nfds);
+ /*
+ * modify timeout parameter to reflect the amount of time not slept
+ * */
+ if (__timeout)
+ {
+ if (vcom_timerisvalid (__timeout))
+ {
+ /* timeout expired */
+ if (timedout)
+ {
+ timerclear (__timeout);
+ }
+ else if (!first_clock_gettime_failed)
+ {
+ rv2 = clock_gettime (CLOCK_MONOTONIC, &now);
+ if (rv2 == -1)
+ {
+ rv = -errno;
+ }
+ else
+ {
+ struct timespec ts_delta;
+ ts_delta = timespec_sub (end_time, now);
+ VCOM_TIMESPEC_TO_TIMEVAL (__timeout, &ts_delta);
+ }
+ }
+ }
+ }
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr, "[%d] vselect2: " "'%04d',='%04d'\n", pid, rv, __nfds);
+
+ return rv;
+}
+
+int
+vcom_select_internal (int __nfds, fd_set * __restrict __readfds,
+ fd_set * __restrict __writefds,
+ fd_set * __restrict __exceptfds,
+ struct timeval *__restrict __timeout)
+{
+ int rv;
+ int new_nfds = 0;
+ int nfd = 0;
+ pid_t pid = getpid ();
+
+ fd_set saved_readfds;
+ fd_set saved_writefds;
+ fd_set saved_exceptfds;
+
+ /* validate __nfds */
+ if (__nfds < 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* validate __timeout */
+ if (__timeout)
+ {
+ /* validate tv_sec */
+ /* bogus */
+ if (__timeout->tv_sec < 0 || __timeout->tv_usec < 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* validate tv_usec */
+ /* TBD: */
+ }
+
+ /* init saved_x fds */
+ if (__readfds)
+ {
+ saved_readfds = *__readfds;
+ /*
+ memcpy (&saved_readfds, __readfds, sizeof (*__readfds));
+ */
+ }
+ else
+ {
+ FD_ZERO (&saved_readfds);
+ }
+
+ if (__writefds)
+ {
+ saved_writefds = *__writefds;
+ /*
+ memcpy (&saved_writefds, __writefds, sizeof (*__writefds));
+ */
+
+ }
+ else
+ {
+ FD_ZERO (&saved_writefds);
+ }
+
+ if (__exceptfds)
+ {
+ saved_exceptfds = *__exceptfds;
+ /*
+ memcpy (&saved_exceptfds, __exceptfds, sizeof (*__exceptfds));
+ */
+
+ }
+ else
+ {
+ FD_ZERO (&saved_exceptfds);
+ }
+
+ /* clear vcom fds */
+ nfd = vcom_fd_clear (__nfds, &new_nfds, __readfds, __writefds, __exceptfds);
+
+ /* set to an invalid value */
+ rv = -2;
+ /* have kernel fds */
+ if (new_nfds)
+ rv = libc_select (new_nfds, __readfds,
+ __writefds, __exceptfds, __timeout);
+
+ if (new_nfds && rv == -1)
+ {
+ /* on error, the file descriptor sets are unmodified */
+ if (__readfds)
+ *__readfds = saved_readfds;
+ if (__writefds)
+ *__writefds = saved_writefds;
+ if (__exceptfds)
+ *__exceptfds = saved_exceptfds;
+ return rv;
+ }
+ else if ((new_nfds && rv != -1) || (rv == -2))
+ {
+ /* restore vcom fds */
+ nfd = vcom_fd_set (__nfds,
+ &new_nfds,
+ __readfds,
+ __writefds,
+ __exceptfds,
+ &saved_readfds, &saved_writefds, &saved_exceptfds);
+ rv = nfd;
+ }
+
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr, "[%d] select: " "'%04d'='%04d'\n", pid, rv, __nfds);
+ return rv;
+}
+
+int
+select (int __nfds, fd_set * __restrict __readfds,
+ fd_set * __restrict __writefds,
+ fd_set * __restrict __exceptfds, struct timeval *__restrict __timeout)
+{
+ int rv = 0;
+ pid_t pid = getpid ();
+
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr, "[%d] select1: " "'%04d'='%04d'\n", pid, rv, __nfds);
+ rv = vcom_select (__nfds, __readfds, __writefds, __exceptfds, __timeout);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr, "[%d] select2: " "'%04d'='%04d'\n", pid, rv, __nfds);
+ if (rv < 0)
+ {
+ errno = -rv;
+ return -1;
+ }
+ return rv;
+}
+
+#ifdef __USE_XOPEN2K
+/*
+ * Same as above only that the TIMEOUT value is given with higher
+ * resolution and a sigmask which is been set temporarily. This
+ * version should be used.
+ *
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+int
+vcom_pselect (int __nfds, fd_set * __restrict __readfds,
+ fd_set * __restrict __writefds,
+ fd_set * __restrict __exceptfds,
+ const struct timespec *__restrict __timeout,
+ const __sigset_t * __restrict __sigmask)
+{
+ int fd;
+ int vcom_nfds = 0;
+
+ for (fd = 0; fd < __nfds; fd++)
+ {
+ if (__readfds && FD_ISSET (fd, __readfds))
+ {
+ if (is_vcom_socket_fd (fd))
+ {
+ vcom_nfds++;
+ }
+ }
+
+ if (__writefds && FD_ISSET (fd, __writefds))
+ {
+ if (is_vcom_socket_fd (fd))
+ {
+ vcom_nfds++;
+ }
+ }
+ if (__exceptfds && FD_ISSET (fd, __exceptfds))
+ {
+ if (is_vcom_socket_fd (fd))
+ {
+ FD_CLR (fd, __exceptfds);
+ }
+ }
+ }
+ return vcom_nfds;
+}
+
+int
+pselect (int __nfds, fd_set * __restrict __readfds,
+ fd_set * __restrict __writefds,
+ fd_set * __restrict __exceptfds,
+ const struct timespec *__restrict __timeout,
+ const __sigset_t * __restrict __sigmask)
+{
+ int rv;
+ int new_nfds = 0;
+ int nfd = 0;
+ pid_t pid = getpid ();
+
+ fd_set saved_readfds;
+ fd_set saved_writefds;
+ fd_set saved_exceptfds;
+
+ /* validate __nfds */
+ if (__nfds < 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* validate __timeout */
+ if (__timeout)
+ {
+ /* validate tv_sec */
+ /* bogus */
+ if (__timeout->tv_sec < 0 || __timeout->tv_nsec < 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* validate tv_usec */
+ /* TBD: */
+ }
+
+ /* init saved fds */
+ if (__readfds)
+ {
+ saved_readfds = *__readfds;
+ /*
+ memcpy (&saved_readfds, __readfds, sizeof (*__readfds));
+ */
+ }
+ else
+ {
+ FD_ZERO (&saved_readfds);
+ }
+
+ if (__writefds)
+ {
+ saved_writefds = *__writefds;
+ /*
+ memcpy (&saved_writefds, __writefds, sizeof (*__writefds));
+ */
+
+ }
+ else
+ {
+ FD_ZERO (&saved_writefds);
+ }
+
+ if (__exceptfds)
+ {
+ saved_exceptfds = *__exceptfds;
+ /*
+ memcpy (&saved_exceptfds, __exceptfds, sizeof (*__exceptfds));
+ */
+
+ }
+ else
+ {
+ FD_ZERO (&saved_exceptfds);
+ }
+
+ /* clear vcom fds */
+ nfd = vcom_fd_clear (__nfds, &new_nfds, __readfds, __writefds, __exceptfds);
+
+ /* set to an invalid value */
+ rv = -2;
+ if (new_nfds)
+ rv = libc_pselect (new_nfds,
+ __readfds,
+ __writefds, __exceptfds, __timeout, __sigmask);
+
+ if (new_nfds && rv == -1)
+ {
+ /* on error, the file descriptor sets are unmodified */
+ if (__readfds)
+ *__readfds = saved_readfds;
+ if (__writefds)
+ *__writefds = saved_writefds;
+ if (__exceptfds)
+ *__exceptfds = saved_exceptfds;
+ return rv;
+ }
+ else if ((new_nfds && rv != -1) || (rv == -2))
+ {
+ /* restore vcom fds */
+ nfd = vcom_fd_set (__nfds,
+ &new_nfds,
+ __readfds,
+ __writefds,
+ __exceptfds,
+ &saved_readfds, &saved_writefds, &saved_exceptfds);
+ rv = nfd;
+ }
+
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr, "[%d] pselect: " "'%04d'='%04d'\n", pid, rv, __nfds);
+ return rv;
+}
+#endif
+
+/*
+ *
+ * Socket specific glibc api
+ *
+ */
+
+/* Create a new socket of type TYPE in domain DOMAIN, using
+ * protocol PROTOCOL. If PROTOCOL is zero, one is chosen
+ * automatically. Returns a file descriptor for the new socket,
+ * or -1 for errors.
+ * RETURN: a valid file descriptor for the new socket,
+ * or -1 for errors.
+ * */
+
+int
+vcom_socket (int __domain, int __type, int __protocol)
+{
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ return vcom_socket_socket (__domain, __type, __protocol);
+}
+
+int
+socket (int __domain, int __type, int __protocol)
+{
+ int rv;
+ pid_t pid = getpid ();
+ pthread_t tid = pthread_self ();
+
+ /* handle domains implemented by vpp */
+ switch (__domain)
+ {
+ case AF_INET:
+ case AF_INET6:
+ /* handle types implemented by vpp */
+ switch (__type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
+ {
+ case SOCK_STREAM:
+ case SOCK_DGRAM:
+ if (VCOM_DEBUG > 0)
+ vcom_socket_main_show ();
+ rv = vcom_socket (__domain, __type, __protocol);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d][%lu (0x%lx)] socket: "
+ "'%04d'= D='%04d', T='%04d', P='%04d'\n",
+ pid, (unsigned long) tid, (unsigned long) tid,
+ rv, __domain, __type, __protocol);
+ if (VCOM_DEBUG > 0)
+ vcom_socket_main_show ();
+ if (rv < 0)
+ {
+ errno = -rv;
+ return -1;
+ }
+ return rv;
+ break;
+
+ default:
+ goto CALL_GLIBC_SOCKET_API;
+ break;
+ }
+
+ break;
+
+ default:
+ goto CALL_GLIBC_SOCKET_API;
+ break;
+ }
+
+CALL_GLIBC_SOCKET_API:
+ return libc_socket (__domain, __type, __protocol);
+}
+
+/*
+ * Create two new sockets, of type TYPE in domain DOMAIN and using
+ * protocol PROTOCOL, which are connected to each other, and put file
+ * descriptors for them in FDS[0] and FDS[1]. If PROTOCOL is zero,
+ * one will be chosen automatically.
+ * Returns 0 on success, -1 for errors.
+ * */
+int
+vcom_socketpair (int __domain, int __type, int __protocol, int __fds[2])
+{
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ return vcom_socket_socketpair (__domain, __type, __protocol, __fds);
+}
+
+int
+socketpair (int __domain, int __type, int __protocol, int __fds[2])
+{
+ int rv;
+ pid_t pid = getpid ();
+
+ /* handle domains implemented by vpp */
+ switch (__domain)
+ {
+ case AF_INET:
+ case AF_INET6:
+ /* handle types implemented by vpp */
+ switch (__type)
+ {
+ case SOCK_STREAM:
+ case SOCK_DGRAM:
+ rv = vcom_socketpair (__domain, __type, __protocol, __fds);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] socketpair: "
+ "'%04d'= D='%04d', T='%04d', P='%04d'\n",
+ pid, rv, __domain, __type, __protocol);
+ if (rv < 0)
+ {
+ errno = -rv;
+ return -1;
+ }
+ return 0;
+ break;
+
+ default:
+ goto CALL_GLIBC_SOCKET_API;
+ break;
+ }
+
+ break;
+
+ default:
+ goto CALL_GLIBC_SOCKET_API;
+ break;
+ }
+
+CALL_GLIBC_SOCKET_API:
+ return libc_socketpair (__domain, __type, __protocol, __fds);
+}
+
+/*
+ * Give the socket FD the local address ADDR
+ * (which is LEN bytes long).
+ * */
+int
+vcom_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
+{
+ int rv;
+
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ /* validate __len */
+ switch (__addr->sa_family)
+ {
+ case AF_INET:
+ if (__len != sizeof (struct sockaddr_in))
+ return -EINVAL;
+ break;
+ case AF_INET6:
+ if (__len != sizeof (struct sockaddr_in6))
+ return -EINVAL;
+ break;
+
+ default:
+ return -1;
+ break;
+ }
+
+ /* handle domains implemented by vpp */
+ switch (__addr->sa_family)
+ {
+ case AF_INET:
+ case AF_INET6:
+ rv = vcom_socket_bind (__fd, __addr, __len);
+ return rv;
+ break;
+
+ default:
+ return -1;
+ break;
+ }
+
+ return -1;
+}
+
+int
+bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
+{
+ int rv;
+ pid_t pid = getpid ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+
+ rv = vcom_bind (__fd, __addr, __len);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] bind: "
+ "'%04d'='%04d', '%p', '%04d'\n",
+ pid, rv, __fd, __addr, __len);
+ if (rv != 0)
+ {
+ errno = -rv;
+ return -1;
+ }
+ return 0;
+ }
+ return libc_bind (__fd, __addr, __len);
+}
+
+/*
+ * Put the local address of FD into *ADDR and its length in *LEN.
+ * */
+int
+vcom_getsockname (int __fd, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __len)
+{
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ return vcom_socket_getsockname (__fd, __addr, __len);
+}
+
+int
+getsockname (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __len)
+{
+ int rv;
+ pid_t pid = getpid ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ rv = vcom_getsockname (__fd, __addr, __len);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] getsockname: "
+ "'%04d'='%04d', '%p', '%p'\n", pid, rv, __fd, __addr, __len);
+ if (rv != 0)
+ {
+ errno = -rv;
+ return -1;
+ }
+ return 0;
+ }
+ return libc_getsockname (__fd, __addr, __len);
+}
+
+/*
+ * Open a connection on socket FD to peer at ADDR
+ * (which LEN bytes long). For connectionless socket types, just set
+ * the default address to send to and the only address from which to
+ * accept transmissions. Return 0 on success, -1 for errors.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+int
+vcom_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
+{
+ int rv = -1;
+
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ /* validate __len */
+ switch (__addr->sa_family)
+ {
+ case AF_INET:
+ if (__len != INET_ADDRSTRLEN)
+ return -1;
+ break;
+ case AF_INET6:
+ if (__len != INET6_ADDRSTRLEN)
+ return -1;
+ break;
+
+ default:
+ return -1;
+ break;
+ }
+
+ /* handle domains implemented by vpp */
+ switch (__addr->sa_family)
+ {
+ case AF_INET:
+ case AF_INET6:
+ rv = vcom_socket_connect (__fd, __addr, __len);
+ break;
+
+ default:
+ return -1;
+ break;
+ }
+
+ return rv;
+}
+
+int
+connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
+{
+ int rv;
+ pid_t pid = getpid ();
+ pthread_t tid = pthread_self ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ rv = vcom_connect (__fd, __addr, __len);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d][%lu (0x%lx)] connect: "
+ "'%04d'='%04d', '%p', '%04d'\n",
+ pid, (unsigned long) tid, (unsigned long) tid,
+ rv, __fd, __addr, __len);
+ if (rv != 0)
+ {
+ errno = -rv;
+ return -1;
+ }
+ return 0;
+ }
+
+ return libc_connect (__fd, __addr, __len);
+}
+
+/*
+ * Put the address of the peer connected to socket FD into *ADDR
+ * (which is *LEN bytes long), and its actual length into *LEN.
+ * */
+int
+vcom_getpeername (int __fd, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __len)
+{
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ return vcom_socket_getpeername (__fd, __addr, __len);
+}
+
+int
+getpeername (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __len)
+{
+ int rv;
+ pid_t pid = getpid ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ rv = vcom_getpeername (__fd, __addr, __len);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] getpeername: "
+ "'%04d'='%04d', '%p', '%p'\n", pid, rv, __fd, __addr, __len);
+ if (rv != 0)
+ {
+ errno = -rv;
+ return -1;
+ }
+ return 0;
+ }
+ return libc_getpeername (__fd, __addr, __len);
+}
+
+/*
+ * Send N bytes of BUF to socket FD. Returns the number sent or -1.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+ssize_t
+vcom_send (int __fd, const void *__buf, size_t __n, int __flags)
+{
+
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ return vcom_socket_send (__fd, (void *) __buf, (int) __n, __flags);
+}
+
+ssize_t
+send (int __fd, const void *__buf, size_t __n, int __flags)
+{
+ ssize_t size;
+ pid_t pid = getpid ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ size = vcom_send (__fd, __buf, __n, __flags);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] send: "
+ "'%04d'='%04d', '%p', '%04d', '%04x'\n",
+ pid, (int) size, __fd, __buf, (int) __n, __flags);
+ if (size < 0)
+ {
+ errno = -size;
+ return -1;
+ }
+ return size;
+ }
+ return libc_send (__fd, __buf, __n, __flags);
+}
+
+/*
+ * Read N bytes into BUF from socket FD.
+ * Returns the number read or -1 for errors.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+ssize_t
+vcom_recv (int __fd, void *__buf, size_t __n, int __flags)
+{
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ return vcom_socket_recv (__fd, __buf, __n, __flags);
+}
+
+ssize_t
+recv (int __fd, void *__buf, size_t __n, int __flags)
+{
+ ssize_t size;
+ pid_t pid = getpid ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ size = vcom_recv (__fd, __buf, __n, __flags);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] recv: "
+ "'%04d'='%04d', '%p', '%04d', '%04x'\n",
+ pid, (int) size, __fd, __buf, (int) __n, __flags);
+ if (size < 0)
+ {
+ errno = -size;
+ return -1;
+ }
+ return size;
+ }
+ return libc_recv (__fd, __buf, __n, __flags);
+}
+
+/*
+ * Send N bytes of BUF on socket FD to peer at address ADDR (which is
+ * ADDR_LEN bytes long). Returns the number sent, or -1 for errors.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+ssize_t
+vcom_sendto (int __fd, const void *__buf, size_t __n, int __flags,
+ __CONST_SOCKADDR_ARG __addr, socklen_t __addr_len)
+{
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ return vcom_socket_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
+}
+
+ssize_t
+sendto (int __fd, const void *__buf, size_t __n, int __flags,
+ __CONST_SOCKADDR_ARG __addr, socklen_t __addr_len)
+{
+ ssize_t size;
+ pid_t pid = getpid ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ size = vcom_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] sendto: "
+ "'%04d'='%04d', '%p', '%04d', '%04x', "
+ "'%p', '%04d'\n",
+ pid, (int) size, __fd, __buf, (int) __n, __flags,
+ __addr, __addr_len);
+ if (size < 0)
+ {
+ errno = -size;
+ return -1;
+ }
+ return size;
+ }
+ return libc_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
+}
+
+/*
+ * Read N bytes into BUF through socket FD.
+ * If ADDR is not NULL, fill in *ADDR_LEN bytes of it with the
+ * address of the sender, and store the actual size of the address
+ * in *ADDR_LEN.
+ * Returns the number of bytes read or -1 for errors.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+ssize_t
+vcom_recvfrom (int __fd, void *__restrict __buf, size_t __n,
+ int __flags,
+ __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
+{
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ return vcom_socket_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
+}
+
+ssize_t
+recvfrom (int __fd, void *__restrict __buf, size_t __n,
+ int __flags,
+ __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
+{
+ ssize_t size;
+ pid_t pid = getpid ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ size = vcom_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] recvfrom: "
+ "'%04d'='%04d', '%p', '%04d', '%04x', "
+ "'%p', '%p'\n",
+ pid, (int) size, __fd, __buf, (int) __n, __flags,
+ __addr, __addr_len);
+ if (size < 0)
+ {
+ errno = -size;
+ return -1;
+ }
+ return size;
+ }
+ return libc_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
+}
+
+/*
+ * Send a message described MESSAGE on socket FD.
+ * Returns the number of bytes sent, or -1 for errors.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+ssize_t
+vcom_sendmsg (int __fd, const struct msghdr * __message, int __flags)
+{
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ return vcom_socket_sendmsg (__fd, __message, __flags);
+}
+
+ssize_t
+sendmsg (int __fd, const struct msghdr * __message, int __flags)
+{
+ ssize_t size;
+ pid_t pid = getpid ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ size = vcom_sendmsg (__fd, __message, __flags);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] sendmsg: "
+ "'%04d'='%04d', '%p', '%04x'\n",
+ pid, (int) size, __fd, __message, __flags);
+ if (size < 0)
+ {
+ errno = -size;
+ return -1;
+ }
+ return size;
+ }
+ return libc_sendmsg (__fd, __message, __flags);
+}
+
+#ifdef __USE_GNU
+/*
+ * Send a VLEN messages as described by VMESSAGES to socket FD.
+ * Returns the number of datagrams successfully written
+ * or -1 for errors.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+int
+vcom_sendmmsg (int __fd, struct mmsghdr *__vmessages,
+ unsigned int __vlen, int __flags)
+{
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ return vcom_socket_sendmmsg (__fd, __message, __vlen, __flags);
+}
+
+int
+sendmmsg (int __fd, struct mmsghdr *__vmessages,
+ unsigned int __vlen, int __flags)
+{
+ ssize_t size;
+ pid_t pid = getpid ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ size = vcom_sendmmsg (__fd, __message, __vlen, __flags);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] sendmmsg: "
+ "'%04d'='%04d', '%p', '%04d', '%04x'\n",
+ pid, (int) size, __fd, __vmessages, __vlen, __flags);
+ if (size < 0)
+ {
+ errno = -size;
+ return -1;
+ }
+ return size;
+ }
+ return libc_sendmmsg (__fd, __message, __vlen, __flags);
+}
+
+#endif
+
+/*
+ * Receive a message as described by MESSAGE from socket FD.
+ * Returns the number of bytes read or -1 for errors.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+ssize_t
+vcom_recvmsg (int __fd, struct msghdr * __message, int __flags)
+{
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ return vcom_socket_recvmsg (__fd, __message, __flags);
+}
+
+ssize_t
+recvmsg (int __fd, struct msghdr * __message, int __flags)
+{
+ ssize_t size;
+ pid_t pid = getpid ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ size = vcom_recvmsg (__fd, __message, __flags);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] recvmsg: "
+ "'%04d'='%04d', '%p', '%04x'\n",
+ pid, (int) size, __fd, __message, __flags);
+ if (size < 0)
+ {
+ errno = -size;
+ return -1;
+ }
+ return size;
+ }
+ return libc_recvmsg (__fd, __message, __flags);
+}
+
+#ifdef __USE_GNU
+/*
+ * Receive up to VLEN messages as described by VMESSAGES from socket FD.
+ * Returns the number of messages received or -1 for errors.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+int
+vcom_recvmmsg (int __fd, struct mmsghdr *__vmessages,
+ unsigned int __vlen, int __flags, struct timespec *__tmo)
+{
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ return vcom_socket_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
+}
+
+int
+recvmmsg (int __fd, struct mmsghdr *__vmessages,
+ unsigned int __vlen, int __flags, struct timespec *__tmo)
+{
+ ssize_t size;
+ pid_t pid = getpid ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ size = vcom_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] recvmmsg: "
+ "'%04d'='%04d', '%p', "
+ "'%04d', '%04x', '%p'\n",
+ pid, (int) size, __fd, __vmessages, __vlen, __flags, __tmo);
+ if (size < 0)
+ {
+ errno = -size;
+ return -1;
+ }
+ return size;
+ }
+ return libc_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
+}
+
+#endif
+
+/*
+ * Put the current value for socket FD's option OPTNAME
+ * at protocol level LEVEL into OPTVAL (which is *OPTLEN bytes long),
+ * and set *OPTLEN to the value's actual length.
+ * Returns 0 on success, -1 for errors.
+ * */
+int
+vcom_getsockopt (int __fd, int __level, int __optname,
+ void *__restrict __optval, socklen_t * __restrict __optlen)
+{
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ return vcom_socket_getsockopt (__fd, __level, __optname,
+ __optval, __optlen);
+}
+
+int
+getsockopt (int __fd, int __level, int __optname,
+ void *__restrict __optval, socklen_t * __restrict __optlen)
+{
+ int rv;
+ pid_t pid = getpid ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ rv = vcom_getsockopt (__fd, __level, __optname, __optval, __optlen);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] getsockopt: "
+ "'%04d'='%04d', '%04d', '%04d', "
+ "'%p', '%p'\n",
+ pid, rv, __fd, __level, __optname, __optval, __optlen);
+ if (rv != 0)
+ {
+ errno = -rv;
+ return -1;
+ }
+ return 0;
+ }
+ return libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
+}
+
+/*
+ * Set socket FD's option OPTNAME at protocol level LEVEL
+ * to *OPTVAL (which is OPTLEN bytes long).
+ * Returns 0 on success, -1 for errors.
+ * */
+int
+vcom_setsockopt (int __fd, int __level, int __optname,
+ const void *__optval, socklen_t __optlen)
+{
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ return vcom_socket_setsockopt (__fd, __level, __optname,
+ __optval, __optlen);
+}
+
+int
+setsockopt (int __fd, int __level, int __optname,
+ const void *__optval, socklen_t __optlen)
+{
+ int rv;
+ pid_t pid = getpid ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ rv = vcom_setsockopt (__fd, __level, __optname, __optval, __optlen);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] setsockopt: "
+ "'%04d'='%04d', '%04d', '%04d', "
+ "'%p', '%04d'\n",
+ pid, rv, __fd, __level, __optname, __optval, __optlen);
+ if (rv != 0)
+ {
+ errno = -rv;
+ return -1;
+ }
+ return 0;
+ }
+ return libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
+}
+
+/*
+ * Prepare to accept connections on socket FD.
+ * N connection requests will be queued before further
+ * requests are refused.
+ * Returns 0 on success, -1 for errors.
+ * */
+int
+vcom_listen (int __fd, int __n)
+{
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ return vcom_socket_listen (__fd, __n);
+}
+
+int
+listen (int __fd, int __n)
+{
+ int rv;
+ pid_t pid = getpid ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ rv = vcom_listen (__fd, __n);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] listen: "
+ "'%04d'='%04d', '%04d'\n", pid, rv, __fd, __n);
+ if (rv != 0)
+ {
+ errno = -rv;
+ return -1;
+ }
+ return 0;
+ }
+ return libc_listen (__fd, __n);
+}
+
+/*
+ * Await a connection on socket FD.
+ * When a connection arrives, open a new socket to communicate
+ * with it, set *ADDR (which is *ADDR_LEN bytes long) to the address
+ * of the connecting peer and *ADDR_LEN to the address's actual
+ * length, and return the new socket's descriptor, or -1 for errors.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+int
+vcom_accept (int __fd, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __addr_len)
+{
+
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+ return vcom_socket_accept (__fd, __addr, __addr_len);
+}
+
+int
+accept (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
+{
+ int rv = -1;
+ pid_t pid = getpid ();
+ pthread_t tid = pthread_self ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ if (VCOM_DEBUG > 0)
+ vcom_socket_main_show ();
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d][%lu (0x%lx)] accept1: "
+ "'%04d'='%04d', '%p', '%p'\n",
+ pid, (unsigned long) tid, (unsigned long) tid,
+ rv, __fd, __addr, __addr_len);
+ rv = vcom_accept (__fd, __addr, __addr_len);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d][%lu (0x%lx)] accept2: "
+ "'%04d'='%04d', '%p', '%p'\n",
+ pid, (unsigned long) tid, (unsigned long) tid,
+ rv, __fd, __addr, __addr_len);
+ if (VCOM_DEBUG > 0)
+ vcom_socket_main_show ();
+ if (rv < 0)
+ {
+ errno = -rv;
+ return -1;
+ }
+ return rv;
+ }
+ return libc_accept (__fd, __addr, __addr_len);
+}
+
+#ifdef __USE_GNU
+/*
+ * Similar to 'accept' but takes an additional parameter to specify
+ * flags.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+int
+vcom_accept4 (int __fd, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __addr_len, int __flags)
+{
+
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+
+ return vcom_socket_accept4 (__fd, __addr, __addr_len, __flags);
+}
+
+int
+accept4 (int __fd, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __addr_len, int __flags)
+{
+ int rv;
+ pid_t pid = getpid ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ if (VCOM_DEBUG > 0)
+ vcom_socket_main_show ();
+ rv = vcom_accept4 (__fd, __addr, __addr_len, __flags);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] accept4: "
+ "'%04d'='%04d', '%p', '%p', '%04x'\n",
+ pid, rv, __fd, __addr, __addr_len, __flags);
+ if (VCOM_DEBUG > 0)
+ vcom_socket_main_show ();
+ if (rv < 0)
+ {
+ errno = -rv;
+ return -1;
+ }
+ return rv;
+ }
+ return libc_accept4 (__fd, __addr, __addr_len, __flags);
+}
+
+#endif
+
+/*
+ * Shut down all or part of the connection open on socket FD.
+ * HOW determines what to shut down:
+ * SHUT_RD = No more receptions;
+ * SHUT_WR = No more transmissions;
+ * SHUT_RDWR = No more receptions or transmissions.
+ * Returns 0 on success, -1 for errors.
+ * */
+int
+vcom_shutdown (int __fd, int __how)
+{
+ if (vcom_init () != 0)
+ {
+ return -1;
+ }
+ return vcom_socket_shutdown (__fd, __how);
+}
+
+int
+shutdown (int __fd, int __how)
+{
+ int rv;
+ pid_t pid = getpid ();
+
+ if (is_vcom_socket_fd (__fd))
+ {
+ rv = vcom_shutdown (__fd, __how);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr,
+ "[%d] shutdown: "
+ "'%04d'='%04d', '%04d'\n", pid, rv, __fd, __how);
+ if (rv != 0)
+ {
+ errno = -rv;
+ return -1;
+ }
+ return 0;
+ }
+ return libc_shutdown (__fd, __how);
+}
+
+void CONSTRUCTOR_ATTRIBUTE vcom_constructor (void);
+
+void DESTRUCTOR_ATTRIBUTE vcom_destructor (void);
+
+void
+vcom_constructor (void)
+{
+ pid_t pid = getpid ();
+
+ swrap_constructor ();
+ if (vcom_init () != 0)
+ {
+ printf ("\n[%d] vcom_constructor...failed!\n", pid);
+ }
+ else
+ {
+ printf ("\n[%d] vcom_constructor...done!\n", pid);
+ }
+}
+
+/*
+ * This function is called when the library is unloaded
+ */
+void
+vcom_destructor (void)
+{
+ pid_t pid = getpid ();
+
+ vcom_destroy ();
+ swrap_destructor ();
+ printf ("\n[%d] vcom_destructor...done!\n", pid);
+}
+
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/vcl-ldpreload/src/libvcl-ldpreload/vcom.h b/vcl-ldpreload/src/libvcl-ldpreload/vcom.h
new file mode 100644
index 0000000..445d8af
--- /dev/null
+++ b/vcl-ldpreload/src/libvcl-ldpreload/vcom.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef included_vcom_h
+#define included_vcom_h
+
+/* VCOM DEBUG flag. Setting this to 1 or 0 turns off
+ ASSERT & other debugging code. */
+#ifndef VCOM_DEBUG
+#define VCOM_DEBUG 0
+#endif
+
+#include <libvcl-ldpreload/vcom_glibc_socket.h>
+
+#define MAX_VCOM_APP_NAME 256
+
+/* Returns 0 on success or -1 on error. */
+extern int vcom_set_app_name (char *__app_name);
+
+/*
+ *
+ * File descriptor based APIs
+ *
+ */
+
+/*
+ * vpp implementation of glibc APIs from <unistd.h>
+ */
+extern int vcom_close (int __fd);
+
+extern ssize_t __wur vcom_read (int __fd, void *__buf, size_t __nbytes);
+
+extern ssize_t __wur vcom_write (int __fd, const void *__buf, size_t __n);
+
+/*
+ * vpp implementation of glibc APIs from <fcntl.h>
+ */
+extern int vcom_fcntl (int __fd, int __cmd, ...);
+
+/*
+ * vpp implementation of glibc APIs from <sys/select.h>
+ */
+extern int
+vcom_select (int __nfds, fd_set * __restrict __readfds,
+ fd_set * __restrict __writefds,
+ fd_set * __restrict __exceptfds,
+ struct timeval *__restrict __timeout);
+
+#ifdef __USE_XOPEN2K
+extern int
+vcom_pselect (int __nfds, fd_set * __restrict __readfds,
+ fd_set * __restrict __writefds,
+ fd_set * __restrict __exceptfds,
+ const struct timespec *__restrict __timeout,
+ const __sigset_t * __restrict __sigmask);
+#endif
+
+/*
+ * vpp implementation of glibc APIs from <sys/socket.h>
+ */
+extern int __THROW vcom_socket (int __domain, int __type, int __protocol);
+
+/* On Linux, the only supported domain for this call is AF_UNIX
+* (or synonymously, AF_LOCAL). Most implementations have the
+* same restriction.
+* vpp does not implement AF_UNIX domain in this release.
+* */
+extern int __THROW
+vcom_socketpair (int __domain, int __type, int __protocol, int __fds[2]);
+
+extern int __THROW
+vcom_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);
+
+extern int __THROW
+vcom_getsockname (int __fd, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __len);
+
+extern int
+vcom_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);
+
+extern int __THROW
+vcom_getpeername (int __fd, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __len);
+
+extern ssize_t
+vcom_send (int __fd, const void *__buf, size_t __n, int __flags);
+
+extern ssize_t vcom_recv (int __fd, void *__buf, size_t __n, int __flags);
+
+extern ssize_t
+vcom_sendto (int __fd, const void *__buf, size_t __n,
+ int __flags, __CONST_SOCKADDR_ARG __addr, socklen_t __addr_len);
+
+extern ssize_t
+vcom_recvfrom (int __fd, void *__restrict __buf,
+ size_t __n, int __flags,
+ __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len);
+
+extern ssize_t
+vcom_sendmsg (int __fd, const struct msghdr *__message, int __flags);
+
+#ifdef __USE_GNU
+extern int
+sendmmsg (int __fd, struct mmsghdr *__vmessages,
+ unsigned int __vlen, int __flags);
+#endif
+
+extern ssize_t vcom_recvmsg (int __fd, struct msghdr *__message, int __flags);
+
+#ifdef __USE_GNU
+extern int
+vcom_recvmmsg (int __fd, struct mmsghdr *__vmessages,
+ unsigned int __vlen, int __flags, struct timespec *__tmo);
+#endif
+
+extern int __THROW
+vcom_getsockopt (int __fd, int __level, int __optname,
+ void *__restrict __optval, socklen_t * __restrict __optlen);
+
+extern int __THROW
+vcom_setsockopt (int __fd, int __level, int __optname,
+ const void *__optval, socklen_t __optlen);
+
+extern int __THROW vcom_listen (int __fd, int __n);
+
+extern int
+vcom_accept (int __fd, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __addr_len);
+
+#ifdef __USE_GNU
+/*
+ * Similar to 'accept' but takes an additional parameter to specify
+ * flags.
+ * */
+/* TBD: implemented later */
+extern int
+vcom_accept4 (int __fd, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __addr_len, int __flags);
+#endif
+
+extern int __THROW vcom_shutdown (int __fd, int __how);
+
+#endif /* included_vcom_h */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/vcl-ldpreload/src/libvcl-ldpreload/vcom_glibc_socket.h b/vcl-ldpreload/src/libvcl-ldpreload/vcom_glibc_socket.h
new file mode 100644
index 0000000..3e43a42
--- /dev/null
+++ b/vcl-ldpreload/src/libvcl-ldpreload/vcom_glibc_socket.h
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef included_vcom_glibc_socket_h
+#define included_vcom_glibc_socket_h
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+
+/*
+ *
+ * Generic glibc fd api
+ *
+ */
+/*
+ * glibc APIs from <unistd.h>
+ */
+
+/* Close the file descriptor FD.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern int close (int __fd);
+
+/* Read NBYTES into BUF from FD. Return the
+ number read, -1 for errors or 0 for EOF.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern ssize_t __wur read (int __fd, void *__buf, size_t __nbytes);
+
+/* Write N bytes of BUF to FD. Return the number written, or -1.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern ssize_t __wur write (int __fd, const void *__buf, size_t __n);
+
+
+/*
+ * glibc APIs from <fcntl.h>
+ */
+
+/* Do the file control operation described by CMD on FD.
+ The remaining arguments are interpreted depending on CMD.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern int fcntl (int __fd, int __cmd, ...);
+
+
+/*
+ * glibc APIs from <sys/select.h>
+ */
+
+/* Check the first NFDS descriptors each in READFDS (if not NULL) for read
+ readiness, in WRITEFDS (if not NULL) for write readiness, and in EXCEPTFDS
+ (if not NULL) for exceptional conditions. If TIMEOUT is not NULL, time out
+ after waiting the interval specified therein. Returns the number of ready
+ descriptors, or -1 for errors.
+
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern int
+select (int __nfds, fd_set * __restrict __readfds,
+ fd_set * __restrict __writefds,
+ fd_set * __restrict __exceptfds,
+ struct timeval *__restrict __timeout);
+
+#ifdef __USE_XOPEN2K
+/* Same as above only that the TIMEOUT value is given with higher
+ resolution and a sigmask which is been set temporarily. This version
+ should be used.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern int
+pselect (int __nfds, fd_set * __restrict __readfds,
+ fd_set * __restrict __writefds,
+ fd_set * __restrict __exceptfds,
+ const struct timespec *__restrict __timeout,
+ const __sigset_t * __restrict __sigmask);
+#endif
+
+
+/*
+ *
+ * Socket specific glibc api
+ *
+ */
+
+/*
+ * glibc APIs from <sys/socket.h>
+ */
+
+/* Create a new socket of type TYPE in domain DOMAIN, using
+ protocol PROTOCOL. If PROTOCOL is zero, one is chosen automatically.
+ Returns a file descriptor for the new socket, or -1 for errors. */
+extern int __THROW socket (int __domain, int __type, int __protocol);
+
+/* Create two new sockets, of type TYPE in domain DOMAIN and using
+ protocol PROTOCOL, which are connected to each other, and put file
+ descriptors for them in FDS[0] and FDS[1]. If PROTOCOL is zero,
+ one will be chosen automatically. Returns 0 on success, -1 for errors. */
+extern int __THROW
+socketpair (int __domain, int __type, int __protocol, int __fds[2]);
+
+/* Give the socket FD the local address ADDR (which is LEN bytes long). */
+extern int __THROW
+bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);
+
+/* Put the local address of FD into *ADDR and its length in *LEN. */
+extern int __THROW
+getsockname (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __len);
+
+/* Open a connection on socket FD to peer at ADDR (which LEN bytes long).
+ For connectionless socket types, just set the default address to send to
+ and the only address from which to accept transmissions.
+ Return 0 on success, -1 for errors.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern int connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);
+
+/* Put the address of the peer connected to socket FD into *ADDR
+ (which is *LEN bytes long), and its actual length into *LEN. */
+extern int __THROW
+getpeername (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __len);
+
+/* Send N bytes of BUF to socket FD. Returns the number sent or -1.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern ssize_t send (int __fd, const void *__buf, size_t __n, int __flags);
+
+/* Read N bytes into BUF from socket FD.
+ Returns the number read or -1 for errors.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern ssize_t recv (int __fd, void *__buf, size_t __n, int __flags);
+
+/* Send N bytes of BUF on socket FD to peer at address ADDR (which is
+ ADDR_LEN bytes long). Returns the number sent, or -1 for errors.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern ssize_t
+sendto (int __fd, const void *__buf, size_t __n,
+ int __flags, __CONST_SOCKADDR_ARG __addr, socklen_t __addr_len);
+
+/* Read N bytes into BUF through socket FD.
+ If ADDR is not NULL, fill in *ADDR_LEN bytes of it with tha address of
+ the sender, and store the actual size of the address in *ADDR_LEN.
+ Returns the number of bytes read or -1 for errors.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern ssize_t
+recvfrom (int __fd, void *__restrict __buf,
+ size_t __n, int __flags,
+ __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len);
+
+/* Send a message described MESSAGE on socket FD.
+ Returns the number of bytes sent, or -1 for errors.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern ssize_t
+sendmsg (int __fd, const struct msghdr *__message, int __flags);
+
+#ifdef __USE_GNU
+/* Send a VLEN messages as described by VMESSAGES to socket FD.
+ Returns the number of datagrams successfully written or -1 for errors.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern int
+sendmmsg (int __fd, struct mmsghdr *__vmessages,
+ unsigned int __vlen, int __flags);
+#endif
+
+/* Receive a message as described by MESSAGE from socket FD.
+ Returns the number of bytes read or -1 for errors.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern ssize_t recvmsg (int __fd, struct msghdr *__message, int __flags);
+
+#ifdef __USE_GNU
+/* Receive up to VLEN messages as described by VMESSAGES from socket FD.
+ Returns the number of messages received or -1 for errors.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern int
+recvmmsg (int __fd, struct mmsghdr *__vmessages,
+ unsigned int __vlen, int __flags, struct timespec *__tmo);
+#endif
+
+
+/* Put the current value for socket FD's option OPTNAME at protocol level LEVEL
+ into OPTVAL (which is *OPTLEN bytes long), and set *OPTLEN to the value's
+ actual length. Returns 0 on success, -1 for errors. */
+extern int __THROW
+getsockopt (int __fd, int __level, int __optname,
+ void *__restrict __optval, socklen_t * __restrict __optlen);
+
+/* Set socket FD's option OPTNAME at protocol level LEVEL
+ to *OPTVAL (which is OPTLEN bytes long).
+ Returns 0 on success, -1 for errors. */
+extern int __THROW
+setsockopt (int __fd, int __level, int __optname,
+ const void *__optval, socklen_t __optlen);
+
+/* Prepare to accept connections on socket FD.
+ N connection requests will be queued before further requests are refused.
+ Returns 0 on success, -1 for errors. */
+extern int __THROW listen (int __fd, int __n);
+
+/* Await a connection on socket FD.
+ When a connection arrives, open a new socket to communicate with it,
+ set *ADDR (which is *ADDR_LEN bytes long) to the address of the connecting
+ peer and *ADDR_LEN to the address's actual length, and return the
+ new socket's descriptor, or -1 for errors.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern int
+accept (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len);
+
+#ifdef __USE_GNU
+/* Similar to 'accept' but takes an additional parameter to specify flags.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+ /* TBD: implemented later */
+extern int
+accept4 (int __fd, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __addr_len, int __flags);
+#endif
+
+/* Shut down all or part of the connection open on socket FD.
+ HOW determines what to shut down:
+ SHUT_RD = No more receptions;
+ SHUT_WR = No more transmissions;
+ SHUT_RDWR = No more receptions or transmissions.
+ Returns 0 on success, -1 for errors. */
+extern int __THROW shutdown (int __fd, int __how);
+
+#endif /* included_vcom_glibc_socket_h */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.c b/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.c
new file mode 100644
index 0000000..8430ab1
--- /dev/null
+++ b/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.c
@@ -0,0 +1,2000 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <unistd.h>
+#include <stdio.h>
+
+#include <vppinfra/types.h>
+#include <vppinfra/hash.h>
+#include <vppinfra/pool.h>
+
+#include <libvcl-ldpreload/vcom_socket.h>
+#include <libvcl-ldpreload/vcom_socket_wrapper.h>
+#include <libvcl-ldpreload/vcom.h>
+
+#include <uri/vppcom.h>
+
+
+/*
+ * VCOM_SOCKET Private definitions and functions.
+ */
+
+typedef struct vcom_socket_main_t_
+{
+ u8 init;
+
+ /* vcom_socket pool */
+ vcom_socket_t *vsockets;
+
+ /* Hash table for socketidx to fd mapping */
+ uword *sockidx_by_fd;
+
+} vcom_socket_main_t;
+
+vcom_socket_main_t vcom_socket_main;
+
+
+/*
+ * Public API functions
+ */
+int
+vcom_socket_open_socket (int domain, int type, int protocol)
+{
+ int rv = -1;
+
+ /* handle domains implemented by vpp */
+ switch (domain)
+ {
+ case AF_INET:
+ case AF_INET6:
+ /* get socket type and
+ * handle the socket types supported by vpp */
+ switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
+ {
+ case SOCK_STREAM:
+ case SOCK_DGRAM:
+ /* the type argument serves a second purpose,
+ * in addition to specifying a socket type,
+ * it may include the bitwise OR of any of
+ * SOCK_NONBLOCK and SOCK_CLOEXEC, to modify
+ * the behavior of socket. */
+ rv = libc_socket (domain, type, protocol);
+ if (rv == -1)
+ rv = -errno;
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ return rv;
+}
+
+int
+vcom_socket_close_socket (int fd)
+{
+ int rv;
+
+ rv = libc_close (fd);
+ if (rv == -1)
+ rv = -errno;
+
+ return rv;
+}
+
+int
+vcom_socket_main_init (void)
+{
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+
+ if (VCOM_DEBUG > 0)
+ printf ("vcom_socket_main_init\n");
+
+ if (!vsm->init)
+ {
+ /* TBD: define FD_MAXSIZE and use it here */
+ pool_alloc (vsm->vsockets, FD_SETSIZE);
+ vsm->sockidx_by_fd = hash_create (0, sizeof (i32));
+ vsm->init = 1;
+ }
+
+ return 0;
+}
+
+void
+vcom_socket_main_destroy (void)
+{
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ vcom_socket_t *vsock;
+
+ if (VCOM_DEBUG > 0)
+ printf ("vcom_socket_main_destroy\n");
+
+ if (vsm->init)
+ {
+ /*
+ * from active list of vsockets,
+ * close socket and vppcom session
+ * */
+
+ /* *INDENT-OFF* */
+ pool_foreach (vsock, vsm->vsockets,
+ ({
+ if (vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
+ {
+ vppcom_session_close (vsock->sid);
+ vcom_socket_close_socket (vsock->fd);
+ vsocket_init (vsock);
+ }
+ }));
+ /* *INDENT-ON* */
+
+ /*
+ * return vsocket element to the pool
+ * */
+
+ /* *INDENT-OFF* */
+ pool_flush (vsock, vsm->vsockets,
+ ({
+ // vsocket_init(vsock);
+ ;
+ }));
+ /* *INDENT-ON* */
+
+ pool_free (vsm->vsockets);
+ hash_free (vsm->sockidx_by_fd);
+ vsm->init = 0;
+ }
+}
+
+void
+vcom_socket_main_show (void)
+{
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ vcom_socket_t *vsock;
+
+ if (vsm->init)
+ {
+ /* from active list of vsockets,
+ * close socket and vppcom session */
+
+ /* *INDENT-OFF* */
+ pool_foreach (vsock, vsm->vsockets,
+ ({
+ printf(
+ "fd='%04d', sid='%08x',type='%-30s'\n",
+ vsock->fd, vsock->sid,
+ vcom_socket_type_str (vsock->type));
+ }));
+ /* *INDENT-ON* */
+ }
+}
+
+
+int
+vcom_socket_is_vcom_fd (int fd)
+{
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+ p = hash_get (vsm->sockidx_by_fd, fd);
+
+ if (p)
+ {
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+ if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
+ return 1;
+ }
+ return 0;
+}
+
+static inline int
+vcom_socket_get_sid (int fd)
+{
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+ p = hash_get (vsm->sockidx_by_fd, fd);
+
+ if (p)
+ {
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+ if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
+ return vsock->sid;
+ }
+ return INVALID_SESSION_ID;
+}
+
+int
+vcom_socket_close (int __fd)
+{
+ int rv = -1;
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+ p = hash_get (vsm->sockidx_by_fd, __fd);
+ if (!p)
+ return -EBADF;
+
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+ if (!vsock)
+ return -ENOTSOCK;
+
+ if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
+ return -EINVAL;
+
+ rv = vppcom_session_close (vsock->sid);
+ rv = vcom_socket_close_socket (vsock->fd);
+
+ vsocket_init (vsock);
+ hash_unset (vsm->sockidx_by_fd, __fd);
+ pool_put (vsm->vsockets, vsock);
+
+ return rv;
+}
+
+ssize_t
+vcom_socket_read (int __fd, void *__buf, size_t __nbytes)
+{
+ int rv = -1;
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+ p = hash_get (vsm->sockidx_by_fd, __fd);
+ if (!p)
+ return -EBADF;
+
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+ if (!vsock)
+ return -ENOTSOCK;
+
+ if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
+ return -EINVAL;
+
+ if (!__buf || __nbytes < 0)
+ {
+ return -EINVAL;
+ }
+
+ rv = vcom_fcntl (__fd, F_GETFL, 0);
+ if (rv < 0)
+ {
+ return rv;
+
+ }
+
+ /* is blocking */
+ if (!(rv & O_NONBLOCK))
+ {
+ do
+ {
+ rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
+ }
+ while (rv == -EAGAIN || rv == -EWOULDBLOCK);
+ return rv;
+ }
+ /* The file descriptor refers to a socket and has been
+ * marked nonblocking(O_NONBLOCK) and the read would
+ * block.
+ * */
+ /* is non blocking */
+ rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
+ return rv;
+}
+
+ssize_t
+vcom_socket_write (int __fd, const void *__buf, size_t __n)
+{
+ int rv = -1;
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+ p = hash_get (vsm->sockidx_by_fd, __fd);
+ if (!p)
+ return -EBADF;
+
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+ if (!vsock)
+ return -ENOTSOCK;
+
+ if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
+ return -EINVAL;
+
+ if (!__buf || __n < 0)
+ {
+ return -EINVAL;
+ }
+
+ rv = vppcom_session_write (vsock->sid, (void *) __buf, __n);
+ return rv;
+}
+
+/*
+ * RETURN: 0 - invalid cmd
+ * 1 - cmd not handled by vcom and vppcom
+ * 2 - cmd handled by vcom socket resource
+ * 3 - cmd handled by vppcom
+ * */
+/* TBD: incomplete list of cmd */
+static int
+vcom_socket_check_fcntl_cmd (int __cmd)
+{
+ switch (__cmd)
+ {
+ /*cmd not handled by vcom and vppcom */
+ /* Fallthrough */
+ case F_DUPFD:
+ case F_DUPFD_CLOEXEC:
+ return 1;
+
+ /* cmd handled by vcom socket resource */
+ /* Fallthrough */
+ case F_GETFD:
+ case F_SETFD:
+ case F_GETFL:
+ case F_SETFL:
+ case F_GETLK:
+ case F_SETLK:
+ case F_SETLKW:
+ case F_GETOWN:
+ case F_SETOWN:
+ return 2;
+
+#if 0
+ /* cmd handled by vppcom */
+ case F_XXXXX:
+ return 3;
+#endif
+ /* invalid cmd */
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+/* TBD: move it to vppcom */
+static int
+vppcom_session_fcntl_va (int __fd, int __cmd, va_list __ap)
+{
+ int rv;
+
+ rv = -EINVAL;
+
+ return rv;
+}
+
+int
+vcom_socket_fcntl_va (int __fd, int __cmd, va_list __ap)
+{
+ int rv = -EBADF;
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+ p = hash_get (vsm->sockidx_by_fd, __fd);
+ if (!p)
+ return -EBADF;
+
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+ if (!vsock)
+ return -ENOTSOCK;
+
+ if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
+ return -EINVAL;
+
+ switch (vcom_socket_check_fcntl_cmd (__cmd))
+ {
+ /* invalid cmd */
+ case 0:
+ rv = -EBADF;
+ break;
+ /*cmd not handled by vcom and vppcom */
+ case 1:
+ rv = -EBADF;
+ break;
+ /* cmd handled by vcom socket resource */
+ case 2:
+ rv = libc_vfcntl (vsock->fd, __cmd, __ap);
+ break;
+ /* cmd handled by vppcom */
+ case 3:
+ rv = vppcom_session_fcntl_va (vsock->sid, __cmd, __ap);
+ break;
+
+ default:
+ rv = -EINVAL;
+ break;
+ }
+
+ return rv;
+}
+
+static inline int
+vcom_socket_fds_2_sid_fds (
+ /* dest */
+ int *vcom_nsid_fds,
+ fd_set * __restrict vcom_rd_sid_fds,
+ fd_set * __restrict vcom_wr_sid_fds,
+ fd_set * __restrict vcom_ex_sid_fds,
+ /* src */
+ int vcom_nfds,
+ fd_set * __restrict vcom_readfds,
+ fd_set * __restrict vcom_writefds,
+ fd_set * __restrict vcom_exceptfds)
+{
+ int rv = 0;
+ int fd;
+ int sid;
+ /* invalid max_sid is -1 */
+ int max_sid = -1;
+ int nsid = 0;
+
+ /*
+ * set sid in sid sets corresponding to fd's in fd sets
+ * compute nsid and vcom_nsid_fds from sid sets
+ */
+
+ for (fd = 0; fd < vcom_nfds; fd++)
+ {
+ /*
+ * F fd set, src
+ * S sid set, dest
+ */
+#define _(S,F) \
+ if ((F) && (S) && FD_ISSET (fd, (F))) \
+ { \
+ sid = vcom_socket_get_sid (fd); \
+ if (sid != INVALID_SESSION_ID) \
+ { \
+ FD_SET (sid, (S)); \
+ if (sid > max_sid) \
+ { \
+ max_sid = sid; \
+ } \
+ ++nsid; \
+ } \
+ else \
+ { \
+ rv = -EBADFD; \
+ goto done; \
+ } \
+ }
+
+
+ _(vcom_rd_sid_fds, vcom_readfds);
+ _(vcom_wr_sid_fds, vcom_writefds);
+ _(vcom_ex_sid_fds, vcom_exceptfds);
+#undef _
+ }
+
+ *vcom_nsid_fds = max_sid != -1 ? max_sid + 1 : 0;
+ rv = nsid;
+
+done:
+ return rv;
+}
+
+/*
+ * PRE: 00. sid sets were derived from fd sets
+ * 01. sid sets were updated with sids that actually changed
+ * status
+ * 02. fd sets still has watched fds
+ *
+ * This function will modify in place fd sets to indicate which fd's
+ * actually changed status(inferred from sid sets)
+ */
+static inline int
+vcom_socket_sid_fds_2_fds (
+ /* dest */
+ int *new_vcom_nfds,
+ int vcom_nfds,
+ fd_set * __restrict vcom_readfds,
+ fd_set * __restrict vcom_writefds,
+ fd_set * __restrict vcom_exceptfds,
+ /* src */
+ int vcom_nsid_fds,
+ fd_set * __restrict vcom_rd_sid_fds,
+ fd_set * __restrict vcom_wr_sid_fds,
+ fd_set * __restrict vcom_ex_sid_fds)
+{
+ int rv = 0;
+ int fd;
+ int sid;
+ /* invalid max_fd is -1 */
+ int max_fd = -1;
+ int nfd = 0;
+
+
+ /*
+ * modify in place fd sets to indicate which fd's
+ * actually changed status(inferred from sid sets)
+ */
+ for (fd = 0; fd < vcom_nfds; fd++)
+ {
+ /*
+ * F fd set, dest
+ * S sid set, src
+ */
+#define _(S,F) \
+ if ((F) && (S) && FD_ISSET (fd, (F))) \
+ { \
+ sid = vcom_socket_get_sid (fd); \
+ if (sid != INVALID_SESSION_ID) \
+ { \
+ if (!FD_ISSET (sid, (S))) \
+ { \
+ FD_CLR(fd, (F)); \
+ } \
+ } \
+ else \
+ { \
+ rv = -EBADFD; \
+ goto done; \
+ } \
+ }
+
+
+ _(vcom_rd_sid_fds, vcom_readfds);
+ _(vcom_wr_sid_fds, vcom_writefds);
+ _(vcom_ex_sid_fds, vcom_exceptfds);
+#undef _
+ }
+
+ /*
+ * compute nfd and new_vcom_nfds from fd sets
+ */
+ for (fd = 0; fd < vcom_nfds; fd++)
+ {
+
+#define _(F) \
+ if ((F) && FD_ISSET (fd, (F))) \
+ { \
+ if (fd > max_fd) \
+ { \
+ max_fd = fd; \
+ } \
+ ++nfd; \
+ }
+
+
+ _(vcom_readfds);
+ _(vcom_writefds);
+ _(vcom_exceptfds);
+#undef _
+
+ }
+
+ *new_vcom_nfds = max_fd != -1 ? max_fd + 1 : 0;
+ rv = nfd;
+
+done:
+ return rv;
+}
+
+/*
+ * PRE:
+ * vom_socket_select is always called with
+ * timeout->tv_sec and timeout->tv_usec set to zero.
+ * hence vppcom_select return immediately.
+ */
+/*
+ * TBD: do{body;} while(timeout conditional); timeout loop
+ */
+int
+vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds,
+ fd_set * __restrict vcom_writefds,
+ fd_set * __restrict vcom_exceptfds,
+ struct timeval *__restrict timeout)
+{
+ int rv = -EBADF;
+ pid_t pid = getpid ();
+
+ int new_vcom_nfds = 0;
+ int new_vcom_nfd = 0;
+
+ /* vcom sid fds */
+ fd_set vcom_rd_sid_fds;
+ fd_set vcom_wr_sid_fds;
+ fd_set vcom_ex_sid_fds;
+ unsigned long vcom_nsid_fds = 0;
+ int vcom_nsid = 0;
+
+ /* in seconds eg. 3.123456789 seconds */
+ double time_to_wait = (double) 0;
+
+ /* validate inputs */
+ if (vcom_nfds < 0)
+ {
+ return -EINVAL;
+ }
+
+ /* convert timeval timeout to double time_to_wait */
+ if (timeout)
+ {
+ if (timeout->tv_sec == 0 && timeout->tv_usec == 0)
+ {
+ /* polling: vppcom_select returns immediately */
+ time_to_wait = (double) 0;
+ }
+ else
+ {
+ /*TBD: use timeval api */
+ time_to_wait = (double) timeout->tv_sec +
+ (double) timeout->tv_usec / (double) 1000000 +
+ (double) (timeout->tv_usec % 1000000) / (double) 1000000;
+ }
+ }
+ else
+ {
+ /*
+ * no timeout: vppcom_select can block indefinitely
+ * waiting for a file descriptor to become ready
+ * */
+ /* set to a phantom value */
+ time_to_wait = ~0;
+ }
+
+ /* zero the sid_sets */
+ /*
+ * F fd set
+ * S sid set
+ */
+#define _(S,F) \
+ if ((F)) \
+ { \
+ FD_ZERO ((S)); \
+ }
+
+
+ _(&vcom_rd_sid_fds, vcom_readfds);
+ _(&vcom_wr_sid_fds, vcom_writefds);
+ _(&vcom_ex_sid_fds, vcom_exceptfds);
+#undef _
+
+ /* populate read, write and except sid_sets */
+ vcom_nsid = vcom_socket_fds_2_sid_fds (
+ /* dest */
+ vcom_readfds || vcom_writefds
+ || vcom_exceptfds ? (int *)
+ &vcom_nsid_fds : NULL,
+ vcom_readfds ? &vcom_rd_sid_fds :
+ NULL,
+ vcom_writefds ? &vcom_wr_sid_fds :
+ NULL,
+ vcom_exceptfds ? &vcom_ex_sid_fds :
+ NULL,
+ /* src */
+ vcom_nfds,
+ vcom_readfds,
+ vcom_writefds, vcom_exceptfds);
+ if (vcom_nsid < 0)
+ {
+ return vcom_nsid;
+ }
+ if (vcom_nsid_fds < 0)
+ {
+ return -EINVAL;
+ }
+
+ rv = vppcom_select (vcom_nsid_fds,
+ vcom_readfds ? (unsigned long *) &vcom_rd_sid_fds :
+ NULL,
+ vcom_writefds ? (unsigned long *) &vcom_wr_sid_fds :
+ NULL,
+ vcom_exceptfds ? (unsigned long *) &vcom_ex_sid_fds :
+ NULL, time_to_wait);
+ if (VCOM_DEBUG > 0)
+ fprintf (stderr, "[%d] vppcom_select: "
+ "'%04d'='%04d'\n", pid, rv, (int) vcom_nsid_fds);
+
+ /* check if any file descriptors changed status */
+ if (rv > 0)
+ {
+ /*
+ * on exit, sets are modified in place to indicate which
+ * file descriptors actually changed status
+ * */
+
+ /*
+ * comply with pre-condition
+ * do not clear vcom fd sets befor calling
+ * vcom_socket_sid_fds_2_fds
+ */
+ new_vcom_nfd = vcom_socket_sid_fds_2_fds (
+ /* dest */
+ &new_vcom_nfds,
+ vcom_nfds,
+ vcom_readfds,
+ vcom_writefds,
+ vcom_exceptfds,
+ /* src */
+ vcom_nsid_fds,
+ vcom_readfds ?
+ &vcom_rd_sid_fds : NULL,
+ vcom_writefds ?
+ &vcom_wr_sid_fds : NULL,
+ vcom_exceptfds ?
+ &vcom_ex_sid_fds : NULL);
+ if (new_vcom_nfd < 0)
+ {
+ return new_vcom_nfd;
+ }
+ if (new_vcom_nfds < 0)
+ {
+ return -EINVAL;
+ }
+ rv = new_vcom_nfd;
+ }
+ return rv;
+}
+
+
+int
+vcom_socket_socket (int __domain, int __type, int __protocol)
+{
+ int rv = -1;
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ vcom_socket_t *vsock;
+
+ i32 fd;
+ i32 sid;
+ i32 sockidx;
+ u8 is_nonblocking = __type & SOCK_NONBLOCK ? 1 : 0;
+ int type = __type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
+
+ fd = vcom_socket_open_socket (__domain, __type, __protocol);
+ if (fd < 0)
+ {
+ rv = fd;
+ goto out;
+ }
+
+ sid = vppcom_session_create (VPPCOM_VRF_DEFAULT,
+ (type == SOCK_DGRAM) ?
+ VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP,
+ is_nonblocking);
+ if (sid < 0)
+ {
+ rv = sid;
+ goto out_close_socket;
+ }
+
+ pool_get (vsm->vsockets, vsock);
+ sockidx = vsock - vsm->vsockets;
+ hash_set (vsm->sockidx_by_fd, fd, sockidx);
+
+ vsocket_set (vsock, fd, sid, SOCKET_TYPE_VPPCOM_BOUND);
+ return fd;
+
+out_close_socket:
+ vcom_socket_close_socket (fd);
+out:
+ return rv;
+}
+
+int
+vcom_socket_socketpair (int __domain, int __type, int __protocol,
+ int __fds[2])
+{
+/* TBD: */
+ return 0;
+}
+
+int
+vcom_socket_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
+{
+ int rv = -1;
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+ vppcom_endpt_t ep;
+
+ p = hash_get (vsm->sockidx_by_fd, __fd);
+ if (!p)
+ return -EBADF;
+
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+ if (!vsock)
+ return -ENOTSOCK;
+
+ if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
+ return -EINVAL;
+
+ if (!__addr)
+ {
+ return -EINVAL;
+ }
+
+ ep.vrf = VPPCOM_VRF_DEFAULT;
+ switch (__addr->sa_family)
+ {
+ case AF_INET:
+ if (__len != sizeof (struct sockaddr_in))
+ {
+ return -EINVAL;
+ }
+ ep.is_ip4 = VPPCOM_IS_IP4;
+ ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
+ ep.port = (u16) ((const struct sockaddr_in *) __addr)->sin_port;
+ break;
+
+ case AF_INET6:
+ if (__len != sizeof (struct sockaddr_in6))
+ {
+ return -EINVAL;
+ }
+ ep.is_ip4 = VPPCOM_IS_IP6;
+ ep.ip = (u8 *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
+ ep.port = (u16) ((const struct sockaddr_in6 *) __addr)->sin6_port;
+ break;
+
+ default:
+ return -1;
+ break;
+ }
+
+ rv = vppcom_session_bind (vsock->sid, &ep);
+ /* TBD: remove libc_bind code snippet
+ * once vppcom implements vppcom_session_getsockname */
+ if (rv == 0)
+ {
+ rv = libc_bind (__fd, __addr, __len);
+ if (rv != 0)
+ {
+ rv = -errno;
+ }
+ }
+ return rv;
+}
+
+int
+vppcom_session_getsockname (int sid, vppcom_endpt_t * ep)
+{
+ /* TBD: move it to vppcom */
+ return 0;
+}
+
+int
+vcom_socket_getsockname (int __fd, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __len)
+{
+ int rv = -1;
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+
+ p = hash_get (vsm->sockidx_by_fd, __fd);
+ if (!p)
+ return -EBADF;
+
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+ if (!vsock)
+ return -ENOTSOCK;
+
+ if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
+ return -EINVAL;
+
+ if (!__addr || !__len)
+ return -EFAULT;
+
+ if (*__len < 0)
+ {
+ return -EINVAL;
+ }
+
+ /* TBD: remove libc_getsockname code snippet
+ * once vppcom implements vppcom_session_getsockname */
+ rv = libc_getsockname (__fd, __addr, __len);
+ if (rv != 0)
+ {
+ rv = -errno;
+ return rv;
+ }
+
+ /* TBD: use the below code snippet when vppcom
+ * implements vppcom_session_getsockname */
+#if 0
+ vppcom_endpt_t ep;
+ ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
+ rv = vppcom_session_getsockname (vsock->sid, &ep);
+ if (rv == 0)
+ {
+ if (ep.vrf == VPPCOM_VRF_DEFAULT)
+ {
+ __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
+ switch (__addr->sa_family)
+ {
+ case AF_INET:
+ ((struct sockaddr_in *) __addr)->sin_port = ep.port;
+ *__len = sizeof (struct sockaddr_in);
+ break;
+
+ case AF_INET6:
+ ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
+ *__len = sizeof (struct sockaddr_in6);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+#endif
+
+ return rv;
+}
+
+int
+vcom_socket_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
+{
+ int rv = -1;
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+ vppcom_endpt_t ep;
+
+ p = hash_get (vsm->sockidx_by_fd, __fd);
+ if (p)
+ {
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+
+ ep.vrf = VPPCOM_VRF_DEFAULT;
+ switch (__addr->sa_family)
+ {
+ case AF_INET:
+ ep.is_ip4 = VPPCOM_IS_IP4;
+ ep.ip =
+ (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
+ ep.port =
+ (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
+ break;
+
+ case AF_INET6:
+ ep.is_ip4 = VPPCOM_IS_IP6;
+ ep.ip =
+ (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
+ ep.port =
+ (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
+ break;
+
+ default:
+ return -1;
+ break;
+ }
+
+ rv = vppcom_session_connect (vsock->sid, &ep);
+ }
+ return rv;
+}
+
+int
+vppcom_session_getpeername (int sid, vppcom_endpt_t * ep)
+{
+ /* TBD: move it to vppcom */
+ return 0;
+}
+
+int
+vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __len)
+{
+ int rv = -1;
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+
+ p = hash_get (vsm->sockidx_by_fd, __fd);
+ if (!p)
+ return -EBADF;
+
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+ if (!vsock)
+ return -ENOTSOCK;
+
+ if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
+ return -EINVAL;
+
+ if (!__addr || !__len)
+ return -EFAULT;
+
+ if (*__len < 0)
+ {
+ return -EINVAL;
+ }
+
+ /* DAW: hack to allow iperf3 to be happy w/ getpeername output */
+ {
+ uint8_t *a;
+ ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
+ ((struct sockaddr_in *) __addr)->sin_port = 0x1000;
+ a = (uint8_t *) & ((struct sockaddr_in *) __addr)->sin_addr;
+ a[0] = 0x7f;
+ a[1] = 0x00;
+ a[2] = 0x00;
+ a[3] = 0x01;
+ *__len = sizeof (struct sockaddr_in);
+ return 0;
+ }
+
+ /* TBD: remove libc_getpeername code snippet
+ * once vppcom implements vppcom_session_getpeername */
+ rv = libc_getpeername (__fd, __addr, __len);
+ if (rv != 0)
+ {
+ rv = -errno;
+ return rv;
+ }
+
+ /* TBD: use the below code snippet when vppcom
+ * implements vppcom_session_getpeername */
+#if 0
+ vppcom_endpt_t ep;
+ ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
+ rv = vppcom_session_getpeername (vsock->sid, &ep);
+ if (rv == 0)
+ {
+ if (ep.vrf == VPPCOM_VRF_DEFAULT)
+ {
+ __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
+ switch (__addr->sa_family)
+ {
+ case AF_INET:
+ ((struct sockaddr_in *) __addr)->sin_port = ep.port;
+ *__len = sizeof (struct sockaddr_in);
+ break;
+
+ case AF_INET6:
+ ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
+ *__len = sizeof (struct sockaddr_in6);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+#endif
+
+ return rv;
+}
+
+ssize_t
+vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags)
+{
+ return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0);
+}
+
+ssize_t
+vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags)
+{
+ int rv = -1;
+ rv = vcom_socket_recvfrom (__fd, __buf, __n, __flags, NULL, 0);
+ return rv;
+}
+
+/*
+ * RETURN 1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET),
+ * 0 otherwise
+ * */
+int
+vcom_socket_is_connection_mode_socket (int __fd)
+{
+ int rv = -1;
+ /* TBD define new vppcom api */
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+ int type;
+ socklen_t optlen;
+
+ p = hash_get (vsm->sockidx_by_fd, __fd);
+
+ if (p)
+ {
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+ if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
+ {
+ optlen = sizeof (type);
+ rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
+ if (rv != 0)
+ {
+ return 0;
+ }
+ /* get socket type */
+ switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
+ {
+ case SOCK_STREAM:
+ case SOCK_SEQPACKET:
+ return 1;
+ break;
+
+ default:
+ return 0;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+ssize_t
+vvppcom_session_sendto (int __sid, const void *__buf, size_t __n,
+ int __flags, __CONST_SOCKADDR_ARG __addr,
+ socklen_t __addr_len)
+{
+ int rv = -1;
+ /* TBD add new vpp api */
+ /* TBD add flags parameter */
+ rv = vppcom_session_write (__sid, (void *) __buf, (int) __n);
+ return rv;
+}
+
+ssize_t
+vcom_socket_sendto (int __fd, const void *__buf, size_t __n,
+ int __flags, __CONST_SOCKADDR_ARG __addr,
+ socklen_t __addr_len)
+{
+ int rv = -1;
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+ p = hash_get (vsm->sockidx_by_fd, __fd);
+ if (!p)
+ return -EBADF;
+
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+ if (!vsock)
+ return -ENOTSOCK;
+
+ if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
+ return -EINVAL;
+
+ if (!__buf || __n < 0)
+ {
+ return -EINVAL;
+ }
+
+ if (vcom_socket_is_connection_mode_socket (__fd))
+ {
+ /* ignore __addr and _addr_len */
+ /* and EISCONN may be returned when they are not NULL and 0 */
+ if ((__addr != NULL) || (__addr_len != 0))
+ {
+ return -EISCONN;
+ }
+ }
+ else
+ {
+ if (!__addr || __addr_len < 0)
+ {
+ return -EDESTADDRREQ;
+ }
+ /* not a vppcom supported address family */
+ if ((__addr->sa_family != AF_INET) || (__addr->sa_family != AF_INET6))
+ {
+ return -EINVAL;
+ }
+ }
+
+ rv = vvppcom_session_sendto (vsock->sid, (void *) __buf, (int) __n,
+ __flags, __addr, __addr_len);
+ return rv;
+}
+
+/* TBD: move it to vppcom */
+static ssize_t
+vppcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n,
+ int __flags, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __addr_len)
+{
+ int rv = -1;
+
+ /* TBD add flags parameter */
+ rv = vppcom_session_read (__sid, __buf, __n);
+ return rv;
+}
+
+ssize_t
+vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
+ int __flags, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __addr_len)
+{
+ int rv = -1;
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+ p = hash_get (vsm->sockidx_by_fd, __fd);
+ if (!p)
+ return -EBADF;
+
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+ if (!vsock)
+ return -ENOTSOCK;
+
+ if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
+ return -EINVAL;
+
+ if (!__buf || __n < 0)
+ {
+ return -EINVAL;
+ }
+
+ if (__addr || __addr_len < 0)
+ {
+ return -EINVAL;
+ }
+
+ rv = vppcom_session_recvfrom (vsock->sid, __buf, __n,
+ __flags, __addr, __addr_len);
+ return rv;
+}
+
+/* TBD: move it to vppcom */
+static ssize_t
+vppcom_sendmsg (int __sid, const struct msghdr *__message, int __flags)
+{
+ int rv = -1;
+ /* rv = vppcom_session_write (__sid, (void *) __message->__buf,
+ (int)__n); */
+ return rv;
+}
+
+ssize_t
+vcom_socket_sendmsg (int __fd, const struct msghdr * __message, int __flags)
+{
+ int rv = -1;
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+ p = hash_get (vsm->sockidx_by_fd, __fd);
+ if (!p)
+ return -EBADF;
+
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+ if (!vsock)
+ return -ENOTSOCK;
+
+ if (vcom_socket_is_connection_mode_socket (__fd))
+ {
+ /* ignore __addr and _addr_len */
+ /* and EISCONN may be returned when they are not NULL and 0 */
+ if ((__message->msg_name != NULL) || (__message->msg_namelen != 0))
+ {
+ return -EISCONN;
+ }
+ }
+ else
+ {
+ /* TBD: validate __message->msg_name and __message->msg_namelen
+ * and return -EINVAL on validation error
+ * */
+ ;
+ }
+
+ rv = vppcom_sendmsg (vsock->sid, __message, __flags);
+
+ return rv;
+}
+
+#ifdef __USE_GNU
+int
+vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages,
+ unsigned int __vlen, int __flags)
+{
+
+ /* TBD: define a new vppcom api */
+ return 0;
+}
+#endif
+
+/* TBD: move it to vppcom */
+static ssize_t
+vppcom_recvmsg (int __sid, struct msghdr *__message, int __flags)
+{
+ int rv = -1;
+ /* rv = vppcom_session_read (__sid, (void *) __message->__buf,
+ (int)__n); */
+ return rv;
+}
+
+ssize_t
+vcom_socket_recvmsg (int __fd, struct msghdr * __message, int __flags)
+{
+ int rv = -1;
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+ p = hash_get (vsm->sockidx_by_fd, __fd);
+ if (!p)
+ return -EBADF;
+
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+ if (!vsock)
+ return -ENOTSOCK;
+
+ if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
+ return -EINVAL;
+
+ if (!__message)
+ {
+ return -EINVAL;
+ }
+
+ /* validate __flags */
+
+ rv = vppcom_recvmsg (vsock->sid, __message, __flags);
+ return rv;
+}
+
+#ifdef __USE_GNU
+int
+vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages,
+ unsigned int __vlen, int __flags,
+ struct timespec *__tmo)
+{
+ /* TBD: define a new vppcom api */
+ return 0;
+}
+#endif
+
+/* TBD: move it to vppcom */
+static int
+vppcom_getsockopt (int __sid, int __level, int __optname,
+ void *__restrict __optval, socklen_t * __restrict __optlen)
+{
+ /* 1. for socket level options that are NOT socket attributes
+ * and that has corresponding vpp options get from vppcom */
+#if 0
+ return 0;
+#endif
+
+ /* 2. unhandled options */
+ return -ENOPROTOOPT;
+}
+
+int
+vcom_socket_getsockopt (int __fd, int __level, int __optname,
+ void *__restrict __optval,
+ socklen_t * __restrict __optlen)
+{
+ int rv = -1;
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+ p = hash_get (vsm->sockidx_by_fd, __fd);
+ if (!p)
+ return -EBADF;
+
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+ if (!vsock)
+ return -ENOTSOCK;
+
+ if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
+ return -EINVAL;
+
+ if (!__optval && !__optlen)
+ return -EFAULT;
+
+ if (*__optlen < 0)
+ {
+ return -EINVAL;
+ }
+
+ switch (__level)
+ {
+ /* handle options at socket level */
+ case SOL_SOCKET:
+ switch (__optname)
+ {
+/*
+ * 1. for socket level options that are socket attributes,
+ * get from libc_getsockopt.
+ * 2. for socket level options that are NOT socket
+ * attributes and that has corresponding vpp options
+ * get from vppcom.
+ * 3. for socket level options unimplemented
+ * return -ENOPROTOOPT */
+ case SO_DEBUG:
+ case SO_DONTROUTE:
+ case SO_BROADCAST:
+ case SO_SNDBUF:
+ case SO_RCVBUF:
+ case SO_REUSEADDR:
+ case SO_REUSEPORT:
+ case SO_KEEPALIVE:
+ case SO_TYPE:
+ case SO_PROTOCOL:
+ case SO_DOMAIN:
+ case SO_ERROR:
+ case SO_OOBINLINE:
+ case SO_NO_CHECK:
+ case SO_PRIORITY:
+ case SO_LINGER:
+ case SO_BSDCOMPAT:
+ case SO_TIMESTAMP:
+ case SO_TIMESTAMPNS:
+ case SO_TIMESTAMPING:
+ case SO_RCVTIMEO:
+ case SO_SNDTIMEO:
+ case SO_RCVLOWAT:
+ case SO_SNDLOWAT:
+ case SO_PASSCRED:
+ case SO_PEERCRED:
+ case SO_PEERNAME:
+ case SO_ACCEPTCONN:
+ case SO_PASSSEC:
+ case SO_PEERSEC:
+ case SO_MARK:
+ case SO_RXQ_OVFL:
+ case SO_WIFI_STATUS:
+ case SO_PEEK_OFF:
+ case SO_NOFCS:
+ case SO_BINDTODEVICE:
+ case SO_GET_FILTER:
+ case SO_LOCK_FILTER:
+ case SO_BPF_EXTENSIONS:
+ case SO_SELECT_ERR_QUEUE:
+#ifdef CONFIG_NET_RX_BUSY_POLL
+ case SO_BUSY_POLL:
+#endif
+ case SO_MAX_PACING_RATE:
+ case SO_INCOMING_CPU:
+ rv = libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
+ if (rv != 0)
+ {
+ rv = -errno;
+ return rv;
+ }
+ break;
+
+ default:
+ /* We implement the SO_SNDLOWAT etc to not be settable
+ * (1003.1g 7).
+ */
+ return -ENOPROTOOPT;
+ }
+
+ break;
+
+ default:
+ /* 1. handle options that are NOT socket level options,
+ * but have corresponding vpp otions. */
+ rv = vppcom_getsockopt (vsock->sid, __level, __optname,
+ __optval, __optlen);
+
+ return rv;
+#if 0
+ /* 2. unhandled options */
+ return -ENOPROTOOPT;
+#endif
+ }
+
+ return rv;
+}
+
+/* TBD: move it to vppcom */
+int
+vppcom_setsockopt (int __fd, int __level, int __optname,
+ const void *__optval, socklen_t __optlen)
+{
+ /* 1. for socket level options that are NOT socket attributes
+ * and that has corresponding vpp options set it from vppcom */
+#if 0
+ return 0;
+#endif
+
+ /* 2. unhandled options */
+ return -ENOPROTOOPT;
+}
+
+int
+vcom_socket_setsockopt (int __fd, int __level, int __optname,
+ const void *__optval, socklen_t __optlen)
+{
+ int rv = -1;
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+ p = hash_get (vsm->sockidx_by_fd, __fd);
+ if (!p)
+ return -EBADF;
+
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+ if (!vsock)
+ return -ENOTSOCK;
+
+ if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
+ return -EINVAL;
+
+ /*
+ * Options without arguments
+ */
+
+ if (__optname == SO_BINDTODEVICE)
+ {
+ rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
+ if (rv != 0)
+ {
+ rv = -errno;
+ }
+ return rv;
+ }
+
+ if (!__optval)
+ return -EFAULT;
+
+ if ((__optlen < 0) || (__optlen < sizeof (int)))
+ return -EINVAL;
+
+ switch (__level)
+ {
+ /* handle options at socket level */
+ case SOL_SOCKET:
+ switch (__optname)
+ {
+ /*
+ * 1. for socket level options that are socket attributes,
+ * set it from libc_getsockopt
+ * 2. for socket level options that are NOT socket
+ * attributes and that has corresponding vpp options
+ * set it from vppcom
+ * 3. for socket level options unimplemented
+ * return -ENOPROTOOPT */
+ case SO_DEBUG:
+ case SO_DONTROUTE:
+ case SO_BROADCAST:
+ case SO_SNDBUF:
+ case SO_RCVBUF:
+ case SO_REUSEADDR:
+ case SO_REUSEPORT:
+ case SO_KEEPALIVE:
+ case SO_TYPE:
+ case SO_PROTOCOL:
+ case SO_DOMAIN:
+ case SO_ERROR:
+ case SO_OOBINLINE:
+ case SO_NO_CHECK:
+ case SO_PRIORITY:
+ case SO_LINGER:
+ case SO_BSDCOMPAT:
+ case SO_TIMESTAMP:
+ case SO_TIMESTAMPNS:
+ case SO_TIMESTAMPING:
+ case SO_RCVTIMEO:
+ case SO_SNDTIMEO:
+ case SO_RCVLOWAT:
+ case SO_SNDLOWAT:
+ case SO_PASSCRED:
+ case SO_PEERCRED:
+ case SO_PEERNAME:
+ case SO_ACCEPTCONN:
+ case SO_PASSSEC:
+ case SO_PEERSEC:
+ case SO_MARK:
+ case SO_RXQ_OVFL:
+ case SO_WIFI_STATUS:
+ case SO_PEEK_OFF:
+ case SO_NOFCS:
+ /*
+ * SO_BINDTODEVICE already handled as
+ * "Options without arguments" */
+ /* case SO_BINDTODEVICE: */
+ case SO_GET_FILTER:
+ case SO_LOCK_FILTER:
+ case SO_BPF_EXTENSIONS:
+ case SO_SELECT_ERR_QUEUE:
+#ifdef CONFIG_NET_RX_BUSY_POLL
+ case SO_BUSY_POLL:
+#endif
+ case SO_MAX_PACING_RATE:
+ case SO_INCOMING_CPU:
+ rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
+ if (rv != 0)
+ {
+ rv = -errno;
+ return rv;
+ }
+ break;
+
+ default:
+ /* We implement the SO_SNDLOWAT etc to not be settable
+ * (1003.1g 7).
+ */
+ return -ENOPROTOOPT;
+ }
+
+ break;
+
+ default:
+ /* 1. handle options that are NOT socket level options,
+ * but have corresponding vpp otions. */
+ rv = vppcom_setsockopt (vsock->sid, __level, __optname,
+ __optval, __optlen);
+ return rv;
+#if 0
+ /* 2. unhandled options */
+ return -ENOPROTOOPT;
+#endif
+ }
+
+ return rv;
+}
+
+int
+vcom_socket_listen (int __fd, int __n)
+{
+ int rv = -1;
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+ p = hash_get (vsm->sockidx_by_fd, __fd);
+ if (p)
+ {
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+
+ /* TBD vppcom to accept __n parameter */
+ rv = vppcom_session_listen (vsock->sid, __n);
+ }
+
+ return rv;
+}
+
+static int
+vcom_socket_connected_socket (int __fd, int __sid,
+ int *__domain,
+ int *__type, int *__protocol, int flags)
+{
+ int rv = -1;
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ vcom_socket_t *vsock;
+
+ i32 fd;
+ i32 sockidx;
+
+ socklen_t optlen;
+
+ optlen = sizeof (*__domain);
+ rv = libc_getsockopt (__fd, SOL_SOCKET, SO_DOMAIN, __domain, &optlen);
+ if (rv != 0)
+ {
+ rv = -errno;
+ goto out;
+ }
+
+ optlen = sizeof (*__type);
+ rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, __type, &optlen);
+ if (rv != 0)
+ {
+ rv = -errno;
+ goto out;
+ }
+
+ optlen = sizeof (*__protocol);
+ rv = libc_getsockopt (__fd, SOL_SOCKET, SO_PROTOCOL, __protocol, &optlen);
+ if (rv != 0)
+ {
+ rv = -errno;
+ goto out;
+ }
+
+ fd = vcom_socket_open_socket (*__domain, *__type | flags, *__protocol);
+ if (fd < 0)
+ {
+ rv = fd;
+ goto out;
+ }
+
+ pool_get (vsm->vsockets, vsock);
+ sockidx = vsock - vsm->vsockets;
+ hash_set (vsm->sockidx_by_fd, fd, sockidx);
+
+ vsocket_set (vsock, fd, __sid, SOCKET_TYPE_VPPCOM_BOUND);
+ return fd;
+
+out:
+ return rv;
+}
+
+/* If flag is 0, then accept4() is the same as accept().
+ * SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags
+ */
+static int
+vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __addr_len, int flags)
+{
+ int rv = -1;
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+ int fd;
+ int sid;
+ int domain;
+ int type;
+ int protocol;
+
+ uint8_t addr8[sizeof (struct in6_addr)];
+ vppcom_endpt_t ep;
+
+ ep.ip = addr8;
+
+ /* validate flags */
+
+ /*
+ * for documentation
+ * switch (flags)
+ * {
+ * case 0:
+ * case SOCK_NONBLOCK:
+ * case SOCK_CLOEXEC:
+ * case SOCK_NONBLOCK | SOCK_CLOEXEC:
+ * break;
+ *
+ * default:
+ * return -1;
+ * }
+ */
+ /* flags can be 0 or can be bitwise OR
+ * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */
+
+ if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC))))
+ {
+ /* TBD: return proper error code */
+ return -1;
+ }
+
+ /* TBD: return proper error code */
+
+ if (!vcom_socket_is_connection_mode_socket (__fd))
+ {
+ return -EOPNOTSUPP;
+ }
+
+ p = hash_get (vsm->sockidx_by_fd, __fd);
+ if (p)
+ {
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+
+
+ rv = vcom_fcntl (vsock->fd, F_GETFL, 0);
+ if (rv < 0)
+ {
+ return rv;
+ }
+
+ /* is blocking */
+ if (!(rv & O_NONBLOCK))
+ {
+ /* socket is not marked as nonblocking
+ * and no pending connections are present
+ * on the queue, accept () blocks the caller
+ * until a connection is present.
+ */
+ rv = vppcom_session_accept (vsock->sid, &ep,
+ -1.0 /* wait forever */ );
+ }
+ else
+ {
+ /* The file descriptor refers to a socket and has been
+ * marked nonblocking(O_NONBLOCK) and the accept would
+ * block.
+ * */
+ /* is non blocking */
+ rv = vppcom_session_accept (vsock->sid, &ep, 0);
+ /* If the socket is marked nonblocking and
+ * no pending connections are present on the
+ * queue, accept fails with the error
+ * EAGAIN or EWOULDBLOCK
+ */
+ if (rv == VPPCOM_ETIMEDOUT)
+ {
+ rv = VPPCOM_EAGAIN;
+ }
+ }
+ if (rv < 0)
+ {
+ return rv;
+ }
+
+ sid = rv;
+
+ /* create a new connected socket resource and set flags
+ * on the new file descriptor.
+ * update vsockets and sockidx_by_fd table
+ * */
+ fd = vcom_socket_connected_socket (__fd, sid,
+ &domain, &type, &protocol, flags);
+ if (fd < 0)
+ {
+ return fd;
+ }
+
+ rv = fd;
+
+ /* TBD populate __addr and __addr_len */
+ /* TBD: The returned address is truncated if the buffer
+ * provided is too small, in this case, __addr_len will
+ * return a value greater than was supplied to the call.*/
+ if (__addr)
+ {
+ if (ep.is_cut_thru)
+ {
+ /* TBD populate __addr and __addr_len */
+ switch (domain)
+ {
+ case AF_INET:
+ ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
+ ((struct sockaddr_in *) __addr)->sin_port = ep.port;
+ memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
+ addr8, sizeof (struct in_addr));
+ /* TBD: populate __addr_len */
+ if (__addr_len)
+ {
+ *__addr_len = sizeof (struct sockaddr_in);
+ }
+ break;
+
+ case AF_INET6:
+ ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
+ ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
+ memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
+ __in6_u.__u6_addr8, addr8,
+ sizeof (struct in6_addr));
+ /* TBD: populate __addr_len */
+ if (__addr_len)
+ {
+ *__addr_len = sizeof (struct sockaddr_in6);
+ }
+ break;
+
+ default:
+ return -EAFNOSUPPORT;
+ }
+ }
+ else
+ {
+ switch (ep.is_ip4)
+ {
+ case VPPCOM_IS_IP4:
+ ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
+ ((struct sockaddr_in *) __addr)->sin_port = ep.port;
+ memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
+ addr8, sizeof (struct in_addr));
+ /* TBD: populate __addr_len */
+ if (__addr_len)
+ {
+ *__addr_len = sizeof (struct sockaddr_in);
+ }
+ break;
+
+ case VPPCOM_IS_IP6:
+ ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
+ ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
+ memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
+ __in6_u.__u6_addr8, addr8,
+ sizeof (struct in6_addr));
+ /* TBD: populate __addr_len */
+ if (__addr_len)
+ {
+ *__addr_len = sizeof (struct sockaddr_in6);
+ }
+ break;
+
+ default:
+ return -EAFNOSUPPORT;
+ }
+ }
+ }
+ else
+ {
+ /* when __addr is NULL, nothing is filled in,
+ * in this case, __addr_len is not used,
+ * and should also be null
+ * */
+ if (__addr_len)
+ {
+ /* TBD: return proper error code */
+ return -1;
+ }
+ }
+ }
+
+ return rv;
+}
+
+int
+vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __addr_len)
+{
+ /* set flags to 0 for accept() */
+ return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0);
+}
+
+#ifdef __USE_GNU
+int
+vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __addr_len, int __flags)
+{
+ /* SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */
+ return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags);
+}
+#endif
+
+/* TBD: move it to vppcom */
+int
+vppcom_session_shutdown (int __fd, int __how)
+{
+ return 0;
+}
+
+int
+vcom_socket_shutdown (int __fd, int __how)
+{
+ int rv = -1;
+ vcom_socket_main_t *vsm = &vcom_socket_main;
+ uword *p;
+ vcom_socket_t *vsock;
+
+ p = hash_get (vsm->sockidx_by_fd, __fd);
+ if (p)
+ {
+ vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+ switch (__how)
+ {
+ case SHUT_RD:
+ case SHUT_WR:
+ case SHUT_RDWR:
+ rv = vppcom_session_shutdown (vsock->sid, __how);
+ return rv;
+ break;
+
+ default:
+ return -EINVAL;
+ break;
+ }
+ }
+
+ return rv;
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.h b/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.h
new file mode 100644
index 0000000..1cd0267
--- /dev/null
+++ b/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef included_vcom_socket_h
+#define included_vcom_socket_h
+
+#include <libvcl-ldpreload/vcom_glibc_socket.h>
+
+#define INVALID_SESSION_ID (~0)
+#define INVALID_FD (~0)
+
+typedef enum
+{
+ SOCKET_TYPE_UNBOUND = 0,
+ SOCKET_TYPE_KERNEL_BOUND,
+ SOCKET_TYPE_VPPCOM_BOUND
+} vcom_socket_type_t;
+
+typedef struct
+{
+ /* file descriptor -
+ * fd 0, 1, 2 have special meaning and are reserved,
+ * -1 denote invalid fd */
+ i32 fd;
+
+ /* session id - -1 denote invalid sid */
+ i32 sid;
+
+ /* socket type */
+ vcom_socket_type_t type;
+
+ /* vcom socket attributes here */
+
+} vcom_socket_t;
+
+static inline char *
+vcom_socket_type_str (vcom_socket_type_t t)
+{
+ switch (t)
+ {
+ case SOCKET_TYPE_UNBOUND:
+ return "SOCKET_TYPE_UNBOUND";
+
+ case SOCKET_TYPE_KERNEL_BOUND:
+ return "SOCKET_TYPE_KERNEL_BOUND";
+
+ case SOCKET_TYPE_VPPCOM_BOUND:
+ return "SOCKET_TYPE_VPPCOM_BOUND";
+
+ default:
+ return "SOCKET_TYPE_UNKNOWN";
+ }
+}
+
+static inline int
+vcom_socket_type_is_vppcom_bound (vcom_socket_type_t t)
+{
+ return t == SOCKET_TYPE_VPPCOM_BOUND;
+}
+
+static inline void
+vsocket_init (vcom_socket_t * vsock)
+{
+ vsock->fd = INVALID_FD;
+ vsock->sid = INVALID_SESSION_ID;
+ vsock->type = SOCKET_TYPE_UNBOUND;
+ /* vcom socket attributes init here */
+}
+
+static inline void
+vsocket_set (vcom_socket_t * vsock, i32 fd, i32 sid, vcom_socket_type_t type)
+{
+ vsock->fd = fd;
+ vsock->sid = sid;
+ vsock->type = type;
+ /* vcom socket attributes set here */
+}
+
+static inline int
+vsocket_is_vppcom_bound (vcom_socket_t * vsock)
+{
+ return vcom_socket_type_is_vppcom_bound (vsock->type);
+}
+
+int vcom_socket_open_socket (int domain, int type, int protocol);
+
+int vcom_socket_close_socket (int fd);
+
+int vcom_socket_main_init (void);
+
+void vcom_socket_main_destroy (void);
+
+void vcom_socket_main_show (void);
+
+int vcom_socket_is_vcom_fd (int fd);
+
+int vcom_socket_close (int __fd);
+
+ssize_t vcom_socket_read (int __fd, void *__buf, size_t __nbytes);
+
+ssize_t vcom_socket_write (int __fd, const void *__buf, size_t __n);
+
+int vcom_socket_fcntl_va (int __fd, int __cmd, va_list __ap);
+
+int
+vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds,
+ fd_set * __restrict vcom_writefds,
+ fd_set * __restrict vcom_exceptfds,
+ struct timeval *__restrict timeout);
+
+
+int vcom_socket_socket (int __domain, int __type, int __protocol);
+
+int
+vcom_socket_socketpair (int __domain, int __type, int __protocol,
+ int __fds[2]);
+
+int vcom_socket_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);
+
+int
+vcom_socket_getsockname (int __fd, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __len);
+
+int
+vcom_socket_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);
+
+int
+vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __len);
+
+ssize_t
+vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags);
+
+ssize_t vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags);
+
+/*
+ * RETURN 1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET),
+ * 0 otherwise
+ * */
+int vcom_socket_is_connection_mode_socket (int __fd);
+
+ssize_t
+vcom_socket_sendto (int __fd, const void *__buf, size_t __n,
+ int __flags, __CONST_SOCKADDR_ARG __addr,
+ socklen_t __addr_len);
+
+ssize_t
+vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
+ int __flags, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __addr_len);
+
+ssize_t
+vcom_socket_sendmsg (int __fd, const struct msghdr *__message, int __flags);
+
+#ifdef __USE_GNU
+int
+vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages,
+ unsigned int __vlen, int __flags);
+#endif
+
+ssize_t vcom_socket_recvmsg (int __fd, struct msghdr *__message, int __flags);
+
+#ifdef __USE_GNU
+int
+vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages,
+ unsigned int __vlen, int __flags,
+ struct timespec *__tmo);
+#endif
+
+int
+vcom_socket_getsockopt (int __fd, int __level, int __optname,
+ void *__restrict __optval,
+ socklen_t * __restrict __optlen);
+
+int
+vcom_socket_setsockopt (int __fd, int __level, int __optname,
+ const void *__optval, socklen_t __optlen);
+
+int vcom_socket_listen (int __fd, int __n);
+
+int
+vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __addr_len);
+
+#ifdef __USE_GNU
+int
+vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr,
+ socklen_t * __restrict __addr_len, int __flags);
+#endif
+
+int vcom_socket_shutdown (int __fd, int __how);
+
+#endif /* included_vcom_socket_h */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.c b/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.c
new file mode 100644
index 0000000..8fe7e1d
--- /dev/null
+++ b/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.c
@@ -0,0 +1,772 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Copyright (c) 2005-2008 Jelmer Vernooij <jelmer@samba.org>
+ * Copyright (C) 2006-2014 Stefan Metzmacher <metze@samba.org>
+ * Copyright (C) 2013-2014 Andreas Schneider <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 <signal.h>
+#include <dlfcn.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include <libvcl-ldpreload/vcom_socket_wrapper.h>
+
+
+enum swrap_dbglvl_e
+{
+ SWRAP_LOG_ERROR = 0,
+ SWRAP_LOG_WARN,
+ SWRAP_LOG_DEBUG,
+ SWRAP_LOG_TRACE
+};
+
+
+/* Macros for accessing mutexes */
+#define SWRAP_LOCK(m) do { \
+ pthread_mutex_lock(&(m ## _mutex)); \
+} while(0)
+
+#define SWRAP_UNLOCK(m) do { \
+ pthread_mutex_unlock(&(m ## _mutex)); \
+} while(0)
+
+/* Add new global locks here please */
+#define SWRAP_LOCK_ALL \
+ SWRAP_LOCK(libc_symbol_binding); \
+
+#define SWRAP_UNLOCK_ALL \
+ SWRAP_UNLOCK(libc_symbol_binding); \
+
+
+
+/* The mutex for accessing the global libc.symbols */
+static pthread_mutex_t libc_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Function prototypes */
+
+#ifdef NDEBUG
+#define SWRAP_LOG(...)
+#else
+static void
+swrap_log (enum swrap_dbglvl_e dbglvl, const char *func,
+ const char *format, ...)
+PRINTF_ATTRIBUTE (3, 4);
+#define SWRAP_LOG(dbglvl, ...) swrap_log((dbglvl), __func__, __VA_ARGS__)
+
+ static void
+ swrap_log (enum swrap_dbglvl_e dbglvl,
+ const char *func, const char *format, ...)
+{
+ char buffer[1024];
+ va_list va;
+ unsigned int lvl = SWRAP_LOG_WARN;
+
+ va_start (va, format);
+ vsnprintf (buffer, sizeof (buffer), format, va);
+ va_end (va);
+
+ if (lvl >= dbglvl)
+ {
+ switch (dbglvl)
+ {
+ case SWRAP_LOG_ERROR:
+ fprintf (stderr,
+ "SWRAP_ERROR(%d) - %s: %s\n",
+ (int) getpid (), func, buffer);
+ break;
+ case SWRAP_LOG_WARN:
+ fprintf (stderr,
+ "SWRAP_WARN(%d) - %s: %s\n",
+ (int) getpid (), func, buffer);
+ break;
+ case SWRAP_LOG_DEBUG:
+ fprintf (stderr,
+ "SWRAP_DEBUG(%d) - %s: %s\n",
+ (int) getpid (), func, buffer);
+ break;
+ case SWRAP_LOG_TRACE:
+ fprintf (stderr,
+ "SWRAP_TRACE(%d) - %s: %s\n",
+ (int) getpid (), func, buffer);
+ break;
+ }
+ }
+}
+#endif
+
+
+/*********************************************************
+ * SWRAP LOADING LIBC FUNCTIONS
+ *********************************************************/
+
+#ifdef HAVE_ACCEPT4
+typedef int (*__libc_accept4) (int sockfd,
+ struct sockaddr * addr,
+ socklen_t * addrlen, int flags);
+#else
+typedef int (*__libc_accept) (int sockfd,
+ struct sockaddr * addr, socklen_t * addrlen);
+#endif
+typedef int (*__libc_bind) (int sockfd,
+ const struct sockaddr * addr, socklen_t addrlen);
+typedef int (*__libc_close) (int fd);
+typedef int (*__libc_connect) (int sockfd,
+ const struct sockaddr * addr,
+ socklen_t addrlen);
+
+#if 0
+/* TBD: dup and dup2 to be implemented later */
+typedef int (*__libc_dup) (int fd);
+typedef int (*__libc_dup2) (int oldfd, int newfd);
+#endif
+
+typedef int (*__libc_fcntl) (int fd, int cmd, ...);
+typedef FILE *(*__libc_fopen) (const char *name, const char *mode);
+#ifdef HAVE_FOPEN64
+typedef FILE *(*__libc_fopen64) (const char *name, const char *mode);
+#endif
+#ifdef HAVE_EVENTFD
+typedef int (*__libc_eventfd) (int count, int flags);
+#endif
+typedef int (*__libc_getpeername) (int sockfd,
+ struct sockaddr * addr,
+ socklen_t * addrlen);
+typedef int (*__libc_getsockname) (int sockfd,
+ struct sockaddr * addr,
+ socklen_t * addrlen);
+typedef int (*__libc_getsockopt) (int sockfd,
+ int level,
+ int optname,
+ void *optval, socklen_t * optlen);
+typedef int (*__libc_ioctl) (int d, unsigned long int request, ...);
+typedef int (*__libc_listen) (int sockfd, int backlog);
+typedef int (*__libc_open) (const char *pathname, int flags, mode_t mode);
+#ifdef HAVE_OPEN64
+typedef int (*__libc_open64) (const char *pathname, int flags, mode_t mode);
+#endif /* HAVE_OPEN64 */
+typedef int (*__libc_openat) (int dirfd, const char *path, int flags, ...);
+typedef int (*__libc_pipe) (int pipefd[2]);
+typedef int (*__libc_read) (int fd, void *buf, size_t count);
+typedef ssize_t (*__libc_readv) (int fd, const struct iovec * iov,
+ int iovcnt);
+typedef int (*__libc_recv) (int sockfd, void *buf, size_t len, int flags);
+typedef int (*__libc_recvfrom) (int sockfd,
+ void *buf,
+ size_t len,
+ int flags,
+ struct sockaddr * src_addr,
+ socklen_t * addrlen);
+typedef int (*__libc_recvmsg) (int sockfd, const struct msghdr * msg,
+ int flags);
+typedef int (*__libc_send) (int sockfd, const void *buf, size_t len,
+ int flags);
+typedef int (*__libc_sendmsg) (int sockfd, const struct msghdr * msg,
+ int flags);
+typedef int (*__libc_sendto) (int sockfd, const void *buf, size_t len,
+ int flags, const struct sockaddr * dst_addr,
+ socklen_t addrlen);
+typedef int (*__libc_setsockopt) (int sockfd, int level, int optname,
+ const void *optval, socklen_t optlen);
+#ifdef HAVE_SIGNALFD
+typedef int (*__libc_signalfd) (int fd, const sigset_t * mask, int flags);
+#endif
+typedef int (*__libc_socket) (int domain, int type, int protocol);
+typedef int (*__libc_socketpair) (int domain, int type, int protocol,
+ int sv[2]);
+#ifdef HAVE_TIMERFD_CREATE
+typedef int (*__libc_timerfd_create) (int clockid, int flags);
+#endif
+typedef ssize_t (*__libc_write) (int fd, const void *buf, size_t count);
+typedef ssize_t (*__libc_writev) (int fd, const struct iovec * iov,
+ int iovcnt);
+
+typedef int (*__libc_shutdown) (int fd, int how);
+
+typedef int (*__libc_select) (int __nfds, fd_set * __restrict __readfds,
+ fd_set * __restrict __writefds,
+ fd_set * __restrict __exceptfds,
+ struct timeval * __restrict __timeout);
+
+#ifdef __USE_XOPEN2K
+typedef int (*__libc_pselect) (int __nfds, fd_set * __restrict __readfds,
+ fd_set * __restrict __writefds,
+ fd_set * __restrict __exceptfds,
+ const struct timespec * __restrict __timeout,
+ const __sigset_t * __restrict __sigmask);
+#endif
+
+#define SWRAP_SYMBOL_ENTRY(i) \
+ union { \
+ __libc_##i f; \
+ void *obj; \
+ } _libc_##i
+
+struct swrap_libc_symbols
+{
+#ifdef HAVE_ACCEPT4
+ SWRAP_SYMBOL_ENTRY (accept4);
+#else
+ SWRAP_SYMBOL_ENTRY (accept);
+#endif
+ SWRAP_SYMBOL_ENTRY (bind);
+ SWRAP_SYMBOL_ENTRY (close);
+ SWRAP_SYMBOL_ENTRY (connect);
+#if 0
+ /* TBD: dup and dup2 to be implemented later */
+ SWRAP_SYMBOL_ENTRY (dup);
+ SWRAP_SYMBOL_ENTRY (dup2);
+#endif
+ SWRAP_SYMBOL_ENTRY (fcntl);
+ SWRAP_SYMBOL_ENTRY (fopen);
+#ifdef HAVE_FOPEN64
+ SWRAP_SYMBOL_ENTRY (fopen64);
+#endif
+#ifdef HAVE_EVENTFD
+ SWRAP_SYMBOL_ENTRY (eventfd);
+#endif
+ SWRAP_SYMBOL_ENTRY (getpeername);
+ SWRAP_SYMBOL_ENTRY (getsockname);
+ SWRAP_SYMBOL_ENTRY (getsockopt);
+ SWRAP_SYMBOL_ENTRY (ioctl);
+ SWRAP_SYMBOL_ENTRY (listen);
+ SWRAP_SYMBOL_ENTRY (open);
+#ifdef HAVE_OPEN64
+ SWRAP_SYMBOL_ENTRY (open64);
+#endif
+ SWRAP_SYMBOL_ENTRY (openat);
+ SWRAP_SYMBOL_ENTRY (pipe);
+ SWRAP_SYMBOL_ENTRY (read);
+ SWRAP_SYMBOL_ENTRY (readv);
+ SWRAP_SYMBOL_ENTRY (recv);
+ SWRAP_SYMBOL_ENTRY (recvfrom);
+ SWRAP_SYMBOL_ENTRY (recvmsg);
+ SWRAP_SYMBOL_ENTRY (send);
+ SWRAP_SYMBOL_ENTRY (sendmsg);
+ SWRAP_SYMBOL_ENTRY (sendto);
+ SWRAP_SYMBOL_ENTRY (setsockopt);
+#ifdef HAVE_SIGNALFD
+ SWRAP_SYMBOL_ENTRY (signalfd);
+#endif
+ SWRAP_SYMBOL_ENTRY (socket);
+ SWRAP_SYMBOL_ENTRY (socketpair);
+#ifdef HAVE_TIMERFD_CREATE
+ SWRAP_SYMBOL_ENTRY (timerfd_create);
+#endif
+ SWRAP_SYMBOL_ENTRY (write);
+ SWRAP_SYMBOL_ENTRY (writev);
+
+ SWRAP_SYMBOL_ENTRY (shutdown);
+ SWRAP_SYMBOL_ENTRY (select);
+#ifdef __USE_XOPEN2K
+ SWRAP_SYMBOL_ENTRY (pselect);
+#endif
+};
+
+struct swrap
+{
+ struct
+ {
+ void *handle;
+ void *socket_handle;
+ struct swrap_libc_symbols symbols;
+ } libc;
+};
+
+static struct swrap swrap;
+
+#define LIBC_NAME "libc.so"
+
+enum swrap_lib
+{
+ SWRAP_LIBC,
+};
+
+#ifndef NDEBUG
+static const char *
+swrap_str_lib (enum swrap_lib lib)
+{
+ switch (lib)
+ {
+ case SWRAP_LIBC:
+ return "libc";
+ }
+
+ /* Compiler would warn us about unhandled enum value if we get here */
+ return "unknown";
+}
+#endif
+
+static void *
+swrap_load_lib_handle (enum swrap_lib lib)
+{
+ int flags = RTLD_LAZY;
+ void *handle = NULL;
+ int i;
+
+#ifdef RTLD_DEEPBIND
+ flags |= RTLD_DEEPBIND;
+#endif
+
+ switch (lib)
+ {
+ case SWRAP_LIBC:
+ handle = swrap.libc.handle;
+#ifdef LIBC_SO
+ if (handle == NULL)
+ {
+ handle = dlopen (LIBC_SO, flags);
+
+ swrap.libc.handle = handle;
+ }
+#endif
+ if (handle == NULL)
+ {
+ for (i = 10; i >= 0; i--)
+ {
+ char soname[256] = { 0 };
+
+ snprintf (soname, sizeof (soname), "libc.so.%d", i);
+ handle = dlopen (soname, flags);
+ if (handle != NULL)
+ {
+ break;
+ }
+ }
+
+ swrap.libc.handle = handle;
+ }
+ break;
+ }
+
+ if (handle == NULL)
+ {
+ SWRAP_LOG (SWRAP_LOG_ERROR,
+ "Failed to dlopen library: %s\n", dlerror ());
+ exit (-1);
+ }
+
+ return handle;
+}
+
+static void *
+_swrap_bind_symbol (enum swrap_lib lib, const char *fn_name)
+{
+ void *handle;
+ void *func;
+
+ handle = swrap_load_lib_handle (lib);
+
+ func = dlsym (handle, fn_name);
+ if (func == NULL)
+ {
+ SWRAP_LOG (SWRAP_LOG_ERROR,
+ "Failed to find %s: %s\n", fn_name, dlerror ());
+ exit (-1);
+ }
+
+ SWRAP_LOG (SWRAP_LOG_TRACE,
+ "Loaded %s from %s", fn_name, swrap_str_lib (lib));
+
+ return func;
+}
+
+#define swrap_bind_symbol_libc(sym_name) \
+ SWRAP_LOCK(libc_symbol_binding); \
+ if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
+ swrap.libc.symbols._libc_##sym_name.obj = \
+ _swrap_bind_symbol(SWRAP_LIBC, #sym_name); \
+ } \
+ SWRAP_UNLOCK(libc_symbol_binding)
+
+/*
+ * IMPORTANT
+ *
+ * Functions especially from libc need to be loaded individually, you can't load
+ * all at once or gdb will segfault at startup. The same applies to valgrind and
+ * has probably something todo with with the linker.
+ * So we need load each function at the point it is called the first time.
+ */
+#ifdef HAVE_ACCEPT4
+int
+libc_accept4 (int sockfd,
+ struct sockaddr *addr, socklen_t * addrlen, int flags)
+{
+ swrap_bind_symbol_libc (accept4);
+
+ return swrap.libc.symbols._libc_accept4.f (sockfd, addr, addrlen, flags);
+}
+
+#else /* HAVE_ACCEPT4 */
+
+int
+libc_accept (int sockfd, struct sockaddr *addr, socklen_t * addrlen)
+{
+ swrap_bind_symbol_libc (accept);
+
+ return swrap.libc.symbols._libc_accept.f (sockfd, addr, addrlen);
+}
+#endif /* HAVE_ACCEPT4 */
+
+int
+libc_bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
+{
+ swrap_bind_symbol_libc (bind);
+
+ return swrap.libc.symbols._libc_bind.f (sockfd, addr, addrlen);
+}
+
+int
+libc_close (int fd)
+{
+ swrap_bind_symbol_libc (close);
+
+ return swrap.libc.symbols._libc_close.f (fd);
+}
+
+int
+libc_connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
+{
+ swrap_bind_symbol_libc (connect);
+
+ return swrap.libc.symbols._libc_connect.f (sockfd, addr, addrlen);
+}
+
+#if 0
+/* TBD: dup and dup2 to be implemented later */
+int
+libc_dup (int fd)
+{
+ swrap_bind_symbol_libc (dup);
+
+ return swrap.libc.symbols._libc_dup.f (fd);
+}
+
+int
+libc_dup2 (int oldfd, int newfd)
+{
+ swrap_bind_symbol_libc (dup2);
+
+ return swrap.libc.symbols._libc_dup2.f (oldfd, newfd);
+}
+#endif
+
+#ifdef HAVE_EVENTFD
+int
+libc_eventfd (int count, int flags)
+{
+ swrap_bind_symbol_libc (eventfd);
+
+ return swrap.libc.symbols._libc_eventfd.f (count, flags);
+}
+#endif
+
+DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE int
+libc_vfcntl (int fd, int cmd, va_list ap)
+{
+ long int args[4];
+ int rc;
+ int i;
+
+ swrap_bind_symbol_libc (fcntl);
+
+ for (i = 0; i < 4; i++)
+ {
+ args[i] = va_arg (ap, long int);
+ }
+
+ rc = swrap.libc.symbols._libc_fcntl.f (fd,
+ cmd,
+ args[0], args[1], args[2], args[3]);
+
+ return rc;
+}
+
+int
+libc_getpeername (int sockfd, struct sockaddr *addr, socklen_t * addrlen)
+{
+ swrap_bind_symbol_libc (getpeername);
+
+ return swrap.libc.symbols._libc_getpeername.f (sockfd, addr, addrlen);
+}
+
+int
+libc_getsockname (int sockfd, struct sockaddr *addr, socklen_t * addrlen)
+{
+ swrap_bind_symbol_libc (getsockname);
+
+ return swrap.libc.symbols._libc_getsockname.f (sockfd, addr, addrlen);
+}
+
+int
+libc_getsockopt (int sockfd,
+ int level, int optname, void *optval, socklen_t * optlen)
+{
+ swrap_bind_symbol_libc (getsockopt);
+
+ return swrap.libc.symbols._libc_getsockopt.f (sockfd,
+ level,
+ optname, optval, optlen);
+}
+
+int
+libc_listen (int sockfd, int backlog)
+{
+ swrap_bind_symbol_libc (listen);
+
+ return swrap.libc.symbols._libc_listen.f (sockfd, backlog);
+}
+
+int
+libc_read (int fd, void *buf, size_t count)
+{
+ swrap_bind_symbol_libc (read);
+
+ return swrap.libc.symbols._libc_read.f (fd, buf, count);
+}
+
+int
+libc_recv (int sockfd, void *buf, size_t len, int flags)
+{
+ swrap_bind_symbol_libc (recv);
+
+ return swrap.libc.symbols._libc_recv.f (sockfd, buf, len, flags);
+}
+
+int
+libc_recvfrom (int sockfd,
+ void *buf,
+ size_t len,
+ int flags, struct sockaddr *src_addr, socklen_t * addrlen)
+{
+ swrap_bind_symbol_libc (recvfrom);
+
+ return swrap.libc.symbols._libc_recvfrom.f (sockfd,
+ buf,
+ len, flags, src_addr, addrlen);
+}
+
+int
+libc_recvmsg (int sockfd, struct msghdr *msg, int flags)
+{
+ swrap_bind_symbol_libc (recvmsg);
+
+ return swrap.libc.symbols._libc_recvmsg.f (sockfd, msg, flags);
+}
+
+int
+libc_send (int sockfd, const void *buf, size_t len, int flags)
+{
+ swrap_bind_symbol_libc (send);
+
+ return swrap.libc.symbols._libc_send.f (sockfd, buf, len, flags);
+}
+
+int
+libc_sendmsg (int sockfd, const struct msghdr *msg, int flags)
+{
+ swrap_bind_symbol_libc (sendmsg);
+
+ return swrap.libc.symbols._libc_sendmsg.f (sockfd, msg, flags);
+}
+
+int
+libc_sendto (int sockfd,
+ const void *buf,
+ size_t len,
+ int flags, const struct sockaddr *dst_addr, socklen_t addrlen)
+{
+ swrap_bind_symbol_libc (sendto);
+
+ return swrap.libc.symbols._libc_sendto.f (sockfd,
+ buf,
+ len, flags, dst_addr, addrlen);
+}
+
+int
+libc_setsockopt (int sockfd,
+ int level, int optname, const void *optval, socklen_t optlen)
+{
+ swrap_bind_symbol_libc (setsockopt);
+
+ return swrap.libc.symbols._libc_setsockopt.f (sockfd,
+ level,
+ optname, optval, optlen);
+}
+
+int
+libc_socket (int domain, int type, int protocol)
+{
+ swrap_bind_symbol_libc (socket);
+
+ return swrap.libc.symbols._libc_socket.f (domain, type, protocol);
+}
+
+int
+libc_socketpair (int domain, int type, int protocol, int sv[2])
+{
+ swrap_bind_symbol_libc (socketpair);
+
+ return swrap.libc.symbols._libc_socketpair.f (domain, type, protocol, sv);
+}
+
+ssize_t
+libc_write (int fd, const void *buf, size_t count)
+{
+ swrap_bind_symbol_libc (write);
+
+ return swrap.libc.symbols._libc_write.f (fd, buf, count);
+}
+
+int
+libc_shutdown (int fd, int how)
+{
+ swrap_bind_symbol_libc (shutdown);
+
+ return swrap.libc.symbols._libc_shutdown.f (fd, how);
+}
+
+int
+libc_select (int __nfds, fd_set * __restrict __readfds,
+ fd_set * __restrict __writefds,
+ fd_set * __restrict __exceptfds,
+ struct timeval *__restrict __timeout)
+{
+ swrap_bind_symbol_libc (select);
+
+ return swrap.libc.symbols._libc_select.f (__nfds, __readfds,
+ __writefds,
+ __exceptfds, __timeout);
+}
+
+#ifdef __USE_XOPEN2K
+int
+libc_pselect (int __nfds, fd_set * __restrict __readfds,
+ fd_set * __restrict __writefds,
+ fd_set * __restrict __exceptfds,
+ const struct timespec *__restrict __timeout,
+ const __sigset_t * __restrict __sigmask)
+{
+ swrap_bind_symbol_libc (pselect);
+
+ return swrap.libc.symbols._libc_pselect.f (__nfds, __readfds,
+ __writefds,
+ __exceptfds,
+ __timeout, __sigmask);
+}
+#endif
+
+static void
+swrap_thread_prepare (void)
+{
+ SWRAP_LOCK_ALL;
+}
+
+static void
+swrap_thread_parent (void)
+{
+ SWRAP_UNLOCK_ALL;
+}
+
+static void
+swrap_thread_child (void)
+{
+ SWRAP_UNLOCK_ALL;
+}
+
+/****************************
+ * CONSTRUCTOR
+ ***************************/
+void
+swrap_constructor (void)
+{
+ /*
+ * If we hold a lock and the application forks, then the child
+ * is not able to unlock the mutex and we are in a deadlock.
+ * This should prevent such deadlocks.
+ */
+ pthread_atfork (&swrap_thread_prepare,
+ &swrap_thread_parent, &swrap_thread_child);
+}
+
+/****************************
+ * DESTRUCTOR
+ ***************************/
+
+/*
+ * This function is called when the library is unloaded and makes sure that
+ * sockets get closed and the unix file for the socket are unlinked.
+ */
+void
+swrap_destructor (void)
+{
+ if (swrap.libc.handle != NULL)
+ {
+ dlclose (swrap.libc.handle);
+ }
+ if (swrap.libc.socket_handle)
+ {
+ dlclose (swrap.libc.socket_handle);
+ }
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.h b/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.h
new file mode 100644
index 0000000..e3590d6
--- /dev/null
+++ b/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Copyright (c) 2005-2008 Jelmer Vernooij <jelmer@samba.org>
+ * Copyright (C) 2006-2014 Stefan Metzmacher <metze@samba.org>
+ * Copyright (C) 2013-2014 Andreas Schneider <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.
+*/
+
+#ifndef included_vcom_socket_wrapper_h
+#define included_vcom_socket_wrapper_h
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/uio.h>
+#include <stdlib.h>
+
+
+/* GCC have printf type attribute check. */
+#ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
+#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
+#else
+#define PRINTF_ATTRIBUTE(a,b)
+#endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
+
+#define HAVE_CONSTRUCTOR_ATTRIBUTE
+#ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
+#define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
+#else
+#define CONSTRUCTOR_ATTRIBUTE
+#endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
+
+#define HAVE_DESTRUCTOR_ATTRIBUTE
+#ifdef HAVE_DESTRUCTOR_ATTRIBUTE
+#define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
+#else
+#define DESTRUCTOR_ATTRIBUTE
+#endif
+
+#define HAVE_ADDRESS_SANITIZER_ATTRIBUTE
+#ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
+#define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE __attribute__((no_sanitize_address))
+#else
+#define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
+#endif
+
+/*
+ * IMPORTANT
+ *
+ * Functions especially from libc need to be loaded individually, you can't load
+ * all at once or gdb will segfault at startup. The same applies to valgrind and
+ * has probably something todo with with the linker.
+ * So we need load each function at the point it is called the first time.
+ */
+#ifdef HAVE_ACCEPT4
+int
+libc_accept4 (int sockfd,
+ struct sockaddr *addr, socklen_t * addrlen, int flags);
+#else /* HAVE_ACCEPT4 */
+int libc_accept (int sockfd, struct sockaddr *addr, socklen_t * addrlen);
+#endif /* HAVE_ACCEPT4 */
+
+int libc_bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+
+int libc_close (int fd);
+
+int libc_connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+
+#if 0
+/* TBD: dup and dup2 to be implemented later */
+int libc_dup (int fd);
+
+int libc_dup2 (int oldfd, int newfd);
+#endif
+
+#ifdef HAVE_EVENTFD
+int libc_eventfd (int count, int flags);
+#endif
+
+DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE int
+libc_vfcntl (int fd, int cmd, va_list ap);
+
+int libc_getpeername (int sockfd, struct sockaddr *addr, socklen_t * addrlen);
+
+int libc_getsockname (int sockfd, struct sockaddr *addr, socklen_t * addrlen);
+
+int
+libc_getsockopt (int sockfd,
+ int level, int optname, void *optval, socklen_t * optlen);
+
+int libc_listen (int sockfd, int backlog);
+
+int libc_read (int fd, void *buf, size_t count);
+
+int libc_recv (int sockfd, void *buf, size_t len, int flags);
+
+int
+libc_recvfrom (int sockfd,
+ void *buf,
+ size_t len,
+ int flags, struct sockaddr *src_addr, socklen_t * addrlen);
+
+int libc_recvmsg (int sockfd, struct msghdr *msg, int flags);
+
+int libc_send (int sockfd, const void *buf, size_t len, int flags);
+
+int libc_sendmsg (int sockfd, const struct msghdr *msg, int flags);
+
+int
+libc_sendto (int sockfd,
+ const void *buf,
+ size_t len,
+ int flags, const struct sockaddr *dst_addr, socklen_t addrlen);
+
+int
+libc_setsockopt (int sockfd,
+ int level, int optname, const void *optval,
+ socklen_t optlen);
+
+int libc_socket (int domain, int type, int protocol);
+
+int libc_socketpair (int domain, int type, int protocol, int sv[2]);
+
+ssize_t libc_write (int fd, const void *buf, size_t count);
+
+int libc_shutdown (int fd, int how);
+
+int
+libc_select (int __nfds, fd_set * __restrict __readfds,
+ fd_set * __restrict __writefds,
+ fd_set * __restrict __exceptfds,
+ struct timeval *__restrict __timeout);
+
+#ifdef __USE_XOPEN2K
+int
+libc_pselect (int __nfds, fd_set * __restrict __readfds,
+ fd_set * __restrict __writefds,
+ fd_set * __restrict __exceptfds,
+ const struct timespec *__restrict __timeout,
+ const __sigset_t * __restrict __sigmask);
+#endif
+
+void swrap_constructor (void);
+
+void swrap_destructor (void);
+
+#endif /* included_vcom_socket_wrapper_h */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/vcl-ldpreload/src/vcl-ldpreload.mk b/vcl-ldpreload/src/vcl-ldpreload.mk
new file mode 100644
index 0000000..001308a
--- /dev/null
+++ b/vcl-ldpreload/src/vcl-ldpreload.mk
@@ -0,0 +1,9 @@
+vcl_ldpreload_configure_depend = vpp-install
+
+vcl_ldpreload_CPPFLAGS = $(call installed_includes_fn, \
+ vppinfra \
+ uri)
+
+vcl_ldpreload_LDFLAGS = $(call installed_libs_fn, \
+ vppinfra \
+ uri)