summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:43:18 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:43:18 +0000
commitcc5717cdf86886c3dbaea40dfc8dc9e501b1cf1f (patch)
tree2dae3914f7c48ebc5d0e27e9d3bdbaea8210a30f
parentInitial commit. (diff)
downloadopentracing-c-wrapper-cc5717cdf86886c3dbaea40dfc8dc9e501b1cf1f.tar.xz
opentracing-c-wrapper-cc5717cdf86886c3dbaea40dfc8dc9e501b1cf1f.zip
Adding upstream version 1.1.3.upstream/1.1.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--.gitignore28
-rw-r--r--AUTHORS1
-rw-r--r--COPYING1
-rw-r--r--ChangeLog3
-rw-r--r--INSTALL368
-rw-r--r--LICENSE202
-rw-r--r--MAINTAINERS1
-rw-r--r--Makefile.am9
-rw-r--r--NEWS0
-rw-r--r--README276
-rw-r--r--TODO0
-rw-r--r--VERSION2
-rw-r--r--configure.ac118
-rw-r--r--include/dbg_malloc.h61
-rw-r--r--include/define.h69
-rw-r--r--include/include.h56
-rw-r--r--include/opentracing-c-wrapper/common.h53
-rw-r--r--include/opentracing-c-wrapper/dbg_malloc.h86
-rw-r--r--include/opentracing-c-wrapper/define.h46
-rw-r--r--include/opentracing-c-wrapper/include.h39
-rw-r--r--include/opentracing-c-wrapper/propagation.h201
-rw-r--r--include/opentracing-c-wrapper/span.h274
-rw-r--r--include/opentracing-c-wrapper/tracer.h93
-rw-r--r--include/opentracing-c-wrapper/util.h110
-rw-r--r--include/opentracing-c-wrapper/value.h60
-rw-r--r--include/span.h94
-rw-r--r--include/tracer.h133
-rw-r--r--include/util.h46
-rw-r--r--include/version.h.in19
-rw-r--r--m4/am-common.m4375
-rw-r--r--m4/am-enable-threads.m444
-rw-r--r--m4/am-host.m444
-rw-r--r--m4/am-with-opentracing.m471
-rw-r--r--opentracing-c-wrapper.pc.in12
-rw-r--r--opentracing-c-wrapper_dbg.pc.in12
-rwxr-xr-xscripts/bootstrap12
-rwxr-xr-xscripts/distclean9
-rw-r--r--src/Makefile.am52
-rw-r--r--src/dbg_malloc.cpp629
-rw-r--r--src/export.map18
-rw-r--r--src/export_dbg.map29
-rw-r--r--src/span.cpp547
-rw-r--r--src/tracer.cpp874
-rw-r--r--src/util.cpp451
-rw-r--r--test/Makefile.am23
-rw-r--r--test/cfg-dd.json5
-rw-r--r--test/cfg-jaeger.yml34
-rw-r--r--test/cfg-zipkin.json4
-rw-r--r--test/debug.h58
-rw-r--r--test/define.h61
-rwxr-xr-xtest/get-opentracing-plugins.sh45
-rw-r--r--test/include.h67
-rw-r--r--test/opentracing.c771
-rw-r--r--test/opentracing.h42
-rw-r--r--test/test.c485
-rw-r--r--test/util.c118
-rw-r--r--test/util.h33
57 files changed, 7374 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2a4a88e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,28 @@
+Makefile
+Makefile.in
+aclocal.m4
+config.log
+config.status
+config/
+configure
+core
+libtool
+m4/libtool.m4
+m4/ltoptions.m4
+m4/ltsugar.m4
+m4/ltversion.m4
+m4/lt~obsolete.m4
+package
+stamp-h1
+test/ot-c-wrapper-test*
+version.h
+.deps/
+.libs/
+*.la
+*.lo
+*.o
+*.orig
+*.pc
+*.rej
+*.so
+_*
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..92b2831
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Miroslav Zagorac <mzagorac@haproxy.com>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..213802f
--- /dev/null
+++ b/COPYING
@@ -0,0 +1 @@
+Copyright 2020 HAProxy Technologies
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..82368aa
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,3 @@
+Wed Jun 9 15:47:38 CEST 2021
+ - added functions otc_tracer_load() and otc_tracer_start()
+
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..8865734
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,368 @@
+Installation Instructions
+*************************
+
+ Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software
+Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved. This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+ Briefly, the shell command './configure && make && make install'
+should configure, build, and install this package. The following
+more-detailed instructions are generic; see the 'README' file for
+instructions specific to this package. Some packages provide this
+'INSTALL' file but do not implement all of the features documented
+below. The lack of an optional feature in a given package is not
+necessarily a bug. More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+ The 'configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a 'Makefile' in each directory of the package.
+It may also create one or more '.h' files containing system-dependent
+definitions. Finally, it creates a shell script 'config.status' that
+you can run in the future to recreate the current configuration, and a
+file 'config.log' containing compiler output (useful mainly for
+debugging 'configure').
+
+ It can also use an optional file (typically called 'config.cache' and
+enabled with '--cache-file=config.cache' or simply '-C') that saves the
+results of its tests to speed up reconfiguring. Caching is disabled by
+default to prevent problems with accidental use of stale cache files.
+
+ If you need to do unusual things to compile the package, please try
+to figure out how 'configure' could check whether to do them, and mail
+diffs or instructions to the address given in the 'README' so they can
+be considered for the next release. If you are using the cache, and at
+some point 'config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file 'configure.ac' (or 'configure.in') is used to create
+'configure' by a program called 'autoconf'. You need 'configure.ac' if
+you want to change it or regenerate 'configure' using a newer version of
+'autoconf'.
+
+ The simplest way to compile this package is:
+
+ 1. 'cd' to the directory containing the package's source code and type
+ './configure' to configure the package for your system.
+
+ Running 'configure' might take a while. While running, it prints
+ some messages telling which features it is checking for.
+
+ 2. Type 'make' to compile the package.
+
+ 3. Optionally, type 'make check' to run any self-tests that come with
+ the package, generally using the just-built uninstalled binaries.
+
+ 4. Type 'make install' to install the programs and any data files and
+ documentation. When installing into a prefix owned by root, it is
+ recommended that the package be configured and built as a regular
+ user, and only the 'make install' phase executed with root
+ privileges.
+
+ 5. Optionally, type 'make installcheck' to repeat any self-tests, but
+ this time using the binaries in their final installed location.
+ This target does not install anything. Running this target as a
+ regular user, particularly if the prior 'make install' required
+ root privileges, verifies that the installation completed
+ correctly.
+
+ 6. You can remove the program binaries and object files from the
+ source code directory by typing 'make clean'. To also remove the
+ files that 'configure' created (so you can compile the package for
+ a different kind of computer), type 'make distclean'. There is
+ also a 'make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+ 7. Often, you can also type 'make uninstall' to remove the installed
+ files again. In practice, not all packages have tested that
+ uninstallation works correctly, even though it is required by the
+ GNU Coding Standards.
+
+ 8. Some packages, particularly those that use Automake, provide 'make
+ distcheck', which can by used by developers to test that all other
+ targets like 'make install' and 'make uninstall' work correctly.
+ This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the 'configure' script does not know about. Run './configure --help'
+for details on some of the pertinent environment variables.
+
+ You can give 'configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here is
+an example:
+
+ ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you can use GNU 'make'. 'cd' to the
+directory where you want the object files and executables to go and run
+the 'configure' script. 'configure' automatically checks for the source
+code in the directory that 'configure' is in and in '..'. This is known
+as a "VPATH" build.
+
+ With a non-GNU 'make', it is safer to compile the package for one
+architecture at a time in the source code directory. After you have
+installed the package for one architecture, use 'make distclean' before
+reconfiguring for another architecture.
+
+ On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple '-arch' options to the
+compiler but only a single '-arch' option to the preprocessor. Like
+this:
+
+ ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CPP="gcc -E" CXXCPP="g++ -E"
+
+ This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the 'lipo' tool if you have problems.
+
+Installation Names
+==================
+
+ By default, 'make install' installs the package's commands under
+'/usr/local/bin', include files under '/usr/local/include', etc. You
+can specify an installation prefix other than '/usr/local' by giving
+'configure' the option '--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+pass the option '--exec-prefix=PREFIX' to 'configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like '--bindir=DIR' to specify different values for particular
+kinds of files. Run 'configure --help' for a list of the directories
+you can set and what kinds of files go in them. In general, the default
+for these options is expressed in terms of '${prefix}', so that
+specifying just '--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+ The most portable way to affect installation locations is to pass the
+correct locations to 'configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+'make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+ The first method involves providing an override variable for each
+affected directory. For example, 'make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+'${prefix}'. Any directories that were specified during 'configure',
+but not in terms of '${prefix}', must each be overridden at install time
+for the entire installation to be relocated. The approach of makefile
+variable overrides for each directory variable is required by the GNU
+Coding Standards, and ideally causes no recompilation. However, some
+platforms have known limitations with the semantics of shared libraries
+that end up requiring recompilation when using this method, particularly
+noticeable in packages that use GNU Libtool.
+
+ The second method involves providing the 'DESTDIR' variable. For
+example, 'make install DESTDIR=/alternate/directory' will prepend
+'/alternate/directory' before all installation names. The approach of
+'DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters. On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of '${prefix}'
+at 'configure' time.
+
+Optional Features
+=================
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving 'configure' the
+option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'.
+
+ Some packages pay attention to '--enable-FEATURE' options to
+'configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to '--with-PACKAGE' options, where PACKAGE
+is something like 'gnu-as' or 'x' (for the X Window System). The
+'README' should mention any '--enable-' and '--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, 'configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the 'configure' options '--x-includes=DIR' and
+'--x-libraries=DIR' to specify their locations.
+
+ Some packages offer the ability to configure how verbose the
+execution of 'make' will be. For these packages, running './configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with 'make V=1'; while running './configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with 'make V=0'.
+
+Particular systems
+==================
+
+ On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC
+is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+ ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+ HP-UX 'make' updates targets which have the same time stamps as their
+prerequisites, which makes it generally unusable when shipped generated
+files such as 'configure' are involved. Use GNU 'make' instead.
+
+ On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its '<wchar.h>' header file. The option '-nodtk' can be used as a
+workaround. If GNU CC is not installed, it is therefore recommended to
+try
+
+ ./configure CC="cc"
+
+and if that doesn't work, try
+
+ ./configure CC="cc -nodtk"
+
+ On Solaris, don't put '/usr/ucb' early in your 'PATH'. This
+directory contains several dysfunctional programs; working variants of
+these programs are available in '/usr/bin'. So, if you need '/usr/ucb'
+in your 'PATH', put it _after_ '/usr/bin'.
+
+ On Haiku, software installed for all users goes in '/boot/common',
+not '/usr/local'. It is recommended to use the following options:
+
+ ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+ There may be some features 'configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on. Usually, assuming the package is built to be run on the
+_same_ architectures, 'configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+'--build=TYPE' option. TYPE can either be a short name for the system
+type, such as 'sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS
+ KERNEL-OS
+
+ See the file 'config.sub' for the possible values of each field. If
+'config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the option '--target=TYPE' to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with '--host=TYPE'.
+
+Sharing Defaults
+================
+
+ If you want to set default values for 'configure' scripts to share,
+you can create a site shell script called 'config.site' that gives
+default values for variables like 'CC', 'cache_file', and 'prefix'.
+'configure' looks for 'PREFIX/share/config.site' if it exists, then
+'PREFIX/etc/config.site' if it exists. Or, you can set the
+'CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all 'configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to 'configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the 'configure' command line, using 'VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified 'gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an
+Autoconf limitation. Until the limitation is lifted, you can use this
+workaround:
+
+ CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+'configure' Invocation
+======================
+
+ 'configure' recognizes the following options to control how it
+operates.
+
+'--help'
+'-h'
+ Print a summary of all of the options to 'configure', and exit.
+
+'--help=short'
+'--help=recursive'
+ Print a summary of the options unique to this package's
+ 'configure', and exit. The 'short' variant lists options used only
+ in the top level, while the 'recursive' variant lists options also
+ present in any nested packages.
+
+'--version'
+'-V'
+ Print the version of Autoconf used to generate the 'configure'
+ script, and exit.
+
+'--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally 'config.cache'. FILE defaults to '/dev/null' to
+ disable caching.
+
+'--config-cache'
+'-C'
+ Alias for '--cache-file=config.cache'.
+
+'--quiet'
+'--silent'
+'-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to '/dev/null' (any error
+ messages will still be shown).
+
+'--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ 'configure' can determine that directory automatically.
+
+'--prefix=DIR'
+ Use DIR as the installation prefix. *note Installation Names:: for
+ more details, including other options available for fine-tuning the
+ installation locations.
+
+'--no-create'
+'-n'
+ Run the configure checks, but stop before creating any output
+ files.
+
+'configure' also accepts some other, not widely useful, options. Run
+'configure --help' for more details.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..6a6a7e9
--- /dev/null
+++ b/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 2020 HAProxy Technologies
+
+ 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.
diff --git a/MAINTAINERS b/MAINTAINERS
new file mode 100644
index 0000000..92b2831
--- /dev/null
+++ b/MAINTAINERS
@@ -0,0 +1 @@
+Miroslav Zagorac <mzagorac@haproxy.com>
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..0bbe80e
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,9 @@
+## Process this file with automake to produce Makefile.in
+##
+SUBDIRS = src test
+DIST_SUBDIRS = src test
+DISTCLEANFILES = _* *~
+CLEANFILES = a.out core gmon.out
+ACLOCAL_AMFLAGS = -I m4
+##
+## Makefile.am ends here
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..438a475
--- /dev/null
+++ b/README
@@ -0,0 +1,276 @@
+ -------------------------------------------------------------
+ C wrapper for the C++ implementation of the OpenTracing API
+ -------------------------------------------------------------
+
+
+Summary
+------------------------------------------------------------------------
+
+ 1. Introduction
+ 2. Build instructions
+ 3. Testing the operation of the library
+ 4. Basic concepts in the OpenTracing
+ 5. Tracing example
+ 6. Known bugs and limitations
+
+
+1. Introduction
+------------------------------------------------------------------------
+
+OpenTracing C Wrapper library was created due to the need to use distributed
+tracing within C programs.
+
+The OpenTracing project (https://opentracing.io/) has published a
+C-language implementation on https://github.com/opentracing/opentracing-c
+but that implementation is incomplete, with the last update on Jun
+27th 2018
+
+This library takes inspiration from the header files in that project but
+implements the proposed functionality fully by wrapping the functional
+C++ library.
+
+
+2. Build instructions
+------------------------------------------------------------------------
+
+Prerequisites for configuring and compiling the OpenTracing C Wrapper:
+----------------------------------------------------------------------
+
+ * GNU GCC Compiler and Development Environment
+ The main components of this system are C standard library, C and C++
+ compilers, make and cmake utilities and other development tools that are
+ not explicitly listed because they depend on the system on which we want
+ to compile the OpenTracing C Wrapper.
+
+ The program itself is very likely possible to compile with another C
+ compiler (non-GCC), but I'm not sure about the other required libraries.
+
+ On debian-like linux systems it is necessary to run the following, in
+ order to install development packages:
+
+ # apt-get install automake autoconf make cmake libc6-dev gcc g++ binutils libtool pkgconf gawk git
+
+ * GNU autoconf
+ https://www.gnu.org/software/autoconf/
+
+ * GNU automake
+ https://www.gnu.org/software/automake/
+
+ * POSIX threads library
+
+ * C++ implementation of the OpenTracing API http://opentracing.io
+ https://github.com/opentracing/opentracing-cpp
+
+ * the tracing plugins (one of the following may be used):
+ * Jaeger SDK with OpenTracing API for C++ binding
+ https://github.com/jaegertracing/jaeger-client-cpp
+
+ * the LightStep distributed tracing library for C++
+ https://github.com/lightstep/lightstep-tracer-cpp
+
+ * OpenTracing implementation for Zipkin in C++
+ https://github.com/rnburn/zipkin-cpp-opentracing
+
+ * Datadog OpenTracing C++ Client
+ https://github.com/DataDog/dd-opentracing-cpp
+
+
+Note: prompt '%' indicates that the command is executed under a unprivileged
+ user, while prompt '#' indicates that the command is executed under the
+ root user.
+
+
+Compiling and installing the opentracing-cpp library:
+-----------------------------------------------------
+
+ The assumption is that we want to install the library in the /opt directory.
+
+ % wget https://github.com/opentracing/opentracing-cpp/archive/v1.5.0.tar.gz
+ % tar xf v1.5.0.tar.gz
+ % cd opentracing-cpp-1.5.0
+ % mkdir build
+ % cd build
+ % cmake -DCMAKE_INSTALL_PREFIX=/opt ..
+ % make
+ # make install
+
+ Of course, we can take another version of the library (or download the master
+ branch via git). For example, this version is used here due to compatibility
+ with the Jaeger plugin, which I mostly used when testing the operation of the
+ program.
+
+
+Compiling and installing the opentracing-c-wrapper library:
+-----------------------------------------------------------
+
+ We will also install this library in the /opt directory, and when configuring
+ the library we must specify where the opentracing-cpp library is located.
+
+ In this example we will install two builds of the library, first the
+ release version and then the debug version.
+
+ % git clone https://github.com/haproxytech/opentracing-c-wrapper.git
+ % cd opentracing-c-wrapper
+ % ./scripts/bootstrap
+ % ./configure --prefix=/opt --with-opentracing=/opt
+ % make
+ # make install
+
+ % ./scripts/distclean
+ % ./scripts/bootstrap
+ % ./configure --prefix=/opt --enable-debug --with-opentracing=/opt
+ % make
+ # make install
+
+
+Compiling the Jaeger tracing plugin:
+------------------------------------
+
+ We will use the 1.5.0 version of the plugin, a newer one can be taken (or
+ the git master branch) if you want to try it (as is the case with previous
+ libraries, you can try a newer version).
+
+ Important note: the GCC version must be at least 4.9 or later.
+
+ % wget https://github.com/jaegertracing/jaeger-client-cpp/archive/v0.5.0.tar.gz
+ % tar xf v0.5.0.tar.gz
+ % cd jaeger-client-cpp-0.5.0
+ % mkdir build
+ % cd build
+ % cmake -DCMAKE_INSTALL_PREFIX=/opt -DJAEGERTRACING_PLUGIN=ON -DHUNTER_CONFIGURATION_TYPES=Release -DHUNTER_BUILD_SHARED_LIBS=OFF ..
+ % make
+
+ After the plugin is compiled, it will be in the current directory.
+ The name of the plugin is libjaegertracing_plugin.so.
+
+ Of course, we can download the precompiled version of the Jaeger plugin
+ (unfortunately, the latest version that can be downloaded is 0.4.2).
+
+ % wget https://github.com/jaegertracing/jaeger-client-cpp/releases/download/v0.4.2/libjaegertracing_plugin.linux_amd64.so
+
+
+3. Testing the operation of the library
+------------------------------------------------------------------------
+
+Testing of the library can be done through the test program, which is located
+in the eponymous directory 'test'. In this directory there is also a script
+with which we can download opentracing plugins from all supported tracers.
+As a script argument we can specify the directory to which the plugins are
+downloaded. If we do not specify this argument then the download is done to
+the current directory. In our example we will place the downloaded plugins
+in the 'test' directory:
+
+ % ./test/get-opentracing-plugins.sh test
+
+The options supported by the test program can be found using the '-h' option:
+
+ % ./test/ot-c-wrapper-test_dbg -h
+
+--- help output -------
+Usage: ot-c-wrapper-test_dbg { -h --help }
+ ot-c-wrapper-test_dbg { -V --version }
+ ot-c-wrapper-test_dbg { [ -R --runcount=VALUE ] | [ -r --runtime=TIME ] } [OPTION]...
+
+Options are:
+ -c, --config=FILE Specify the configuration for the used tracer.
+ -d, --debug=LEVEL Enable and specify the debug mode level (default: 0).
+ -h, --help Show this text.
+ -p, --plugin=FILE Specify the OpenTracing compatible plugin library.
+ -R, --runcount=VALUE Execute this program a certain number of passes (0 = unlimited).
+ -r, --runtime=TIME Run this program for a certain amount of time (ms, 0 = unlimited).
+ -t, --threads=VALUE Specify the number of threads (default: 1000).
+ -V, --version Show program version.
+
+Copyright 2020 HAProxy Technologies
+SPDX-License-Identifier: Apache-2.0
+--- help output -------
+
+In case we did not use the '--enable-debug' option when configuring the
+library, the test program will be named ot-c-wrapper-test.
+
+
+Example of using the test program:
+
+ % ./test/ot-c-wrapper-test -r 10000 -c test/cfg-jaeger.yml -p test/libjaeger_opentracing_plugin-0.4.2.so
+
+'-r' is the option that must be specified when launching a program. It is
+used to prevent the test program from starting unnecessarily when testing the
+program options, or printing the test program help. In addition, with this
+option, the test program runtime is set. If the time is set to 0, the test
+program runtime is unlimited. In the example above, the runtime is set to
+10 seconds.
+
+With the '-c' option, we specify the configuration of the used tracer (in this
+case it is Jeager); while the '-p' option selects the plugin library that the
+selected tracer uses.
+
+
+The test directory contains several configurations prepared for supported
+tracers:
+ - cfg-dd.json - Datadog tracer
+ - cfg-jaeger.yml - Jaeger tracer
+ - cfg-zipkin.json - Zipkin tracer
+
+
+Jaeger docker image installation:
+---------------------------------
+
+ Installation instructions can be found on the website
+ https://www.jaegertracing.io/download/. For the impatient, here we will list
+ how the image to test the operation of the tracer system can be installed
+ without much reading of the documentation.
+
+ # docker pull jaegertracing/all-in-one:latest
+ # docker run -d --name jaeger -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 -p 5775:5775/udp -p 6831:6831/udp -p 6832:6832/udp -p 5778:5778 -p 16686:16686 -p 14268:14268 -p 9411:9411 jaegertracing/all-in-one:latest
+
+ The last command will also initialize and run the Jaeger container.
+ If we want to use that container later, it can be started and stopped
+ in the classic way, using the 'docker container start/stop' commands.
+
+
+4. Basic concepts in the OpenTracing
+------------------------------------------------------------------------
+
+Basic concepts of the OpenTracing can be read on the OpenTracing documentation
+website https://opentracing.io/docs/overview/.
+
+Here we will list only the most important elements of distributed tracing and
+these are 'trace', 'span' and 'span context'. Trace is a description of the
+complete transaction we want to record in the tracing system. A span is an
+operation that represents a unit of work that is recorded in a tracing system.
+Span context is a group of information related to a particular span that is
+passed on to the system (from service to service). Using this context, we can
+add new spans to already open trace (or supplement data in already open spans).
+
+An individual span may contain one or more tags, logs and baggage items.
+The tag is a key-value element that is valid for the entire span. Log is a
+key-value element that allows you to write some data at a certain time, it
+can be used for debugging. A baggage item is a key-value data pair that can
+be used for the duration of an entire trace, from the moment it is added to
+the span.
+
+
+5. Tracing example
+------------------------------------------------------------------------
+
+In the example, whose source is in the 'test' directory, the operation of the
+OpenTracing C Wrapper is checked. 5 spans are created in which tags, logs and
+baggage are placed; and data propagation via text map, http header and binary
+data is checked.
+
+root span |------------------------------------------------------------------|
+ span #1 |----------------------------------------------------------|
+ text map propagation |--------------------------------------------------|
+ http headers propagation |------------------------------------------|
+ binary data propagation |----------------------------------|
+
+
+6. Known bugs and limitations
+------------------------------------------------------------------------
+
+The library does not know whether the data was sent to the tracer or not,
+because sending is done in a separate thread that does not affect the
+operation of the rest of the program.
+
+One should not exaggerate with the number of competing threads that send data
+to their tracers as this can slow down the sending of data to the tracer.
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/TODO
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..e1ca911
--- /dev/null
+++ b/VERSION
@@ -0,0 +1,2 @@
+Package Version: 1.1.3
+Library Version: 1:1:1
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..784a3f5
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,118 @@
+dnl Process this file with autoconf to produce a configure script.
+dnl
+dnl configure.ac - Miroslav Zagorac <mzagorac@haproxy.com>
+
+AC_PREREQ([2.69])
+AC_COPYRIGHT([Copyright (C) 2020 HAProxy Technologies])
+AC_INIT(m4_esyscmd_s([basename ${PWD}]), m4_esyscmd_s([awk '/Package/ { print $3 }' VERSION]), [mzagorac@haproxy.com])
+AC_CONFIG_MACRO_DIR([m4])
+AX_VARIABLE_SET([LIB_VERSION], m4_esyscmd_s([awk '/Library/ { print $3 }' VERSION]))
+
+echo "*** configuring for ${PACKAGE_NAME} v${PACKAGE_VERSION}, lib v${LIB_VERSION} ***"
+
+AC_PREFIX_DEFAULT([/usr])
+AC_CONFIG_AUX_DIR([config])
+AM_INIT_AUTOMAKE([1.13])
+AX_VARIABLES_INIT
+AM_SILENT_RULES([yes])
+AX_HOST
+
+dnl Check for source directory.
+dnl
+AC_CONFIG_SRCDIR([src/tracer.cpp])
+AC_CONFIG_HEADERS([config/config.h])
+
+AX_PROG_PKGCONFIG
+PKG_INSTALLDIR
+
+dnl Set the compiler, preprocessor, and file extensions.
+dnl
+AC_LANG([C])
+
+dnl Checking command line options.
+dnl
+AX_ENABLE_DEBUG
+AX_ENABLE_GPROF
+AX_ENABLE_THREADS
+dnl
+dnl Misc
+dnl
+AX_WITH_OPENTRACING
+
+dnl Checks for programs.
+dnl
+AC_PROG_CXX
+AC_PROG_CC
+AC_PROG_INSTALL
+
+dnl Initialize libtool
+dnl
+LT_INIT
+
+dnl Checks for header files.
+dnl
+AC_CHECK_HEADERS([fcntl.h inttypes.h malloc.h stdint.h stdlib.h string.h sys/time.h unistd.h])
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+dnl
+AC_CHECK_HEADER_STDBOOL
+AC_TYPE_UINT8_T
+AC_TYPE_INT64_T
+AC_TYPE_UINT64_T
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+AC_TYPE_SSIZE_T
+
+dnl Checks for libraries.
+dnl
+
+dnl Checks for library functions.
+dnl
+AC_FUNC_ERROR_AT_LINE
+AC_FUNC_STRERROR_R
+AC_CHECK_FUNCS([clock_gettime gettimeofday memmove memset strchr strdup strndup])
+AC_CHECK_FUNCS([mallinfo])
+
+dnl Set the compiler flags
+dnl
+AX_PROG_CC_SET([])
+AX_PROG_CXX_SET([])
+
+AM_CONDITIONAL([WANT_DEBUG], [test "${enable_debug}" = "yes"])
+
+AX_VARIABLES_SET
+
+AX_VARIABLE_SET([OPENTRACING_C_WRAPPER_CPPFLAGS], [ ${OPENTRACING_CPPFLAGS} ${THREADS_CPPFLAGS} ])
+AX_VARIABLE_SET([OPENTRACING_C_WRAPPER_CFLAGS], [ ${OPENTRACING_CFLAGS} ${THREADS_CFLAGS} ])
+AX_VARIABLE_SET([OPENTRACING_C_WRAPPER_CXXFLAGS], [ ${OPENTRACING_CXXFLAGS} ${THREADS_CXXFLAGS} ])
+AX_VARIABLE_SET([OPENTRACING_C_WRAPPER_LDFLAGS], [ ${OPENTRACING_LDFLAGS} ${THREADS_LDFLAGS} ])
+AX_VARIABLE_SET([OPENTRACING_C_WRAPPER_LIBS], [ ${OPENTRACING_LIBS} ${THREADS_LIBS} ])
+
+AC_SUBST([OPENTRACING_C_WRAPPER_CPPFLAGS])
+AC_SUBST([OPENTRACING_C_WRAPPER_CFLAGS])
+AC_SUBST([OPENTRACING_C_WRAPPER_CXXFLAGS])
+AC_SUBST([OPENTRACING_C_WRAPPER_LDFLAGS])
+AC_SUBST([OPENTRACING_C_WRAPPER_LIBS])
+
+dnl version.h
+dnl
+CONFIGURE_OPTIONS="${ac_configure_args}"
+AC_SUBST([DATE])
+AC_SUBST([PACKAGE_VERSION])
+AC_SUBST([LIB_VERSION])
+AC_SUBST([CONFIGURE_OPTIONS])
+
+AC_CONFIG_FILES([Makefile src/Makefile test/Makefile include/version.h opentracing-c-wrapper.pc opentracing-c-wrapper_dbg.pc])
+AC_OUTPUT
+
+AX_SHOW_CONFIG
+
+
+AH_TOP([
+#ifndef _COMMON_CONFIG_H
+#define _COMMON_CONFIG_H
+])
+
+AH_BOTTOM([
+#endif /* _COMMON_CONFIG_H */
+])
diff --git a/include/dbg_malloc.h b/include/dbg_malloc.h
new file mode 100644
index 0000000..b0557be
--- /dev/null
+++ b/include/dbg_malloc.h
@@ -0,0 +1,61 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 _OPENTRACING_C_WRAPPER_DBG_MALLOC_H_
+#define _OPENTRACING_C_WRAPPER_DBG_MALLOC_H_
+
+#ifdef HAVE_MALLOC_H
+# include <malloc.h>
+#endif
+
+
+#define DBG_MEM(l,s,f, ...) \
+ do { \
+ if (dbg_mem == nullptr) \
+ /* Do nothing. */; \
+ else if (!(l) || (dbg_mem->level & (1 << (l)))) \
+ (void)fprintf((s), f "\n", ##__VA_ARGS__); \
+ } while (0)
+#define DBG_MEM_ERR(f, ...) DBG_MEM(0, stderr, "MEM_ERROR: " f, ##__VA_ARGS__)
+#define DBG_MEM_INFO(l,f, ...) DBG_MEM((l), stdout, f, ##__VA_ARGS__)
+
+/* 8 bytes - dBgM (dBgM ^ 0xffffffff) */
+#define DBG_MEM_MAGIC UINT64_C(0x6442674d9bbd98b2)
+#define DBG_MEM_SIZE(n) ((n) + sizeof(struct otc_dbg_mem_metadata))
+#define DBG_MEM_PTR(p) DBG_MEM_SIZE(OT_CAST_TYPEOF(uint8_t *, (p)))
+#define DBG_MEM_DATA(p) OT_CAST_TYPEOF(struct otc_dbg_mem_metadata *, OT_CAST_TYPEOF(uint8_t *, (p)) - DBG_MEM_SIZE(0))
+#define DBG_MEM_RETURN(p) (((p) == nullptr) ? nullptr : DBG_MEM_PTR(p))
+
+struct otc_dbg_mem_metadata {
+ struct otc_dbg_mem_data *data;
+ uint64_t magic;
+};
+
+#ifdef __sun
+#define PRI_MI "lu"
+#else
+#define PRI_MI "d"
+#endif
+
+#endif /* _OPENTRACING_C_WRAPPER_DBG_MALLOC_H_ */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/include/define.h b/include/define.h
new file mode 100644
index 0000000..1e63fef
--- /dev/null
+++ b/include/define.h
@@ -0,0 +1,69 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 _OPENTRACING_C_WRAPPER_DEFINE_H_
+#define _OPENTRACING_C_WRAPPER_DEFINE_H_
+
+#undef OT_THREADS_NO_LOCKING
+
+#ifdef USE_THREADS
+# define __THR __thread
+#else
+# define __THR
+#endif
+
+#ifdef DEBUG
+# define OTC_DBG_MEM
+# define OT_IFDEF_DBG(a,b) a
+# define OT_EXT_MALLOC(s) otc_ext_malloc(__func__, __LINE__, (s))
+# define OT_EXT_FREE_CLEAR(a) do { if ((a) != nullptr) { otc_ext_free(__func__, __LINE__, a); (a) = nullptr; } } while (0)
+#else
+# define OT_IFDEF_DBG(a,b) b
+# define OT_EXT_MALLOC(s) otc_ext_malloc(s)
+# define OT_EXT_FREE_CLEAR(a) do { if ((a) != nullptr) { otc_ext_free(a); (a) = nullptr; } } while (0)
+#endif
+
+#define OT_FREE(a) do { if ((a) != nullptr) OTC_DBG_FREE(a); } while (0)
+#define OT_FREE_CLEAR(a) do { if ((a) != nullptr) { OTC_DBG_FREE(a); (a) = nullptr; } } while (0)
+
+#define OT_IN_RANGE(v,a,b) (((v) >= (a)) && ((v) <= (b)))
+#define OT_SPAN_KEY_IS_VALID(a) OT_IN_RANGE((a)->idx, 0, ot_span.key - 1)
+#define OT_SPAN_IS_VALID(a) (((a) != nullptr) && OT_SPAN_KEY_IS_VALID(a))
+#define OT_CTX_KEY_IS_VALID(a) OT_IN_RANGE((a)->idx, 0, ot_span_context.key - 1)
+#define OT_CTX_IS_VALID(a) (((a) != nullptr) && (OT_SPAN_IS_VALID((a)->span) || OT_CTX_KEY_IS_VALID(a)))
+
+#define OT_CAST_CONST(t,e) const_cast<t>(e)
+#define OT_CAST_STAT(t,e) static_cast<t>(e)
+#define OT_CAST_REINTERPRET(t,e) reinterpret_cast<t>(e)
+#define OT_CAST_TYPEOF(t,e) OT_CAST_REINTERPRET(typeof(t), (e))
+
+#ifdef __cplusplus
+# define __CPLUSPLUS_DECL_BEGIN extern "C" {
+# define __CPLUSPLUS_DECL_END }
+#else
+# define __CPLUSPLUS_DECL_BEGIN
+# define __CPLUSPLUS_DECL_END
+#endif
+
+#endif /* _OPENTRACING_C_WRAPPER_DEFINE_H_ */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/include/include.h b/include/include.h
new file mode 100644
index 0000000..85c1b88
--- /dev/null
+++ b/include/include.h
@@ -0,0 +1,56 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 _OPENTRACING_C_WRAPPER_INCLUDE_H_
+#define _OPENTRACING_C_WRAPPER_INCLUDE_H_
+
+#include <cstdio>
+#include <cinttypes>
+#include <stdbool.h>
+#include <sstream>
+#include <mutex>
+
+#include <opentracing/dynamic_load.h>
+#include <opentracing/version.h>
+
+#include "config.h"
+#include "define.h"
+#ifdef DEBUG
+# include "dbg_malloc.h"
+#endif
+
+#include "opentracing-c-wrapper/define.h"
+#include "opentracing-c-wrapper/dbg_malloc.h"
+#include "opentracing-c-wrapper/common.h"
+#include "opentracing-c-wrapper/util.h"
+#include "opentracing-c-wrapper/value.h"
+#include "opentracing-c-wrapper/span.h"
+#include "opentracing-c-wrapper/propagation.h"
+#include "opentracing-c-wrapper/tracer.h"
+
+#include "span.h"
+#include "tracer.h"
+#include "util.h"
+
+#endif /* _OPENTRACING_C_WRAPPER_INCLUDE_H_ */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/include/opentracing-c-wrapper/common.h b/include/opentracing-c-wrapper/common.h
new file mode 100644
index 0000000..2bac541
--- /dev/null
+++ b/include/opentracing-c-wrapper/common.h
@@ -0,0 +1,53 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 OPENTRACING_C_WRAPPER_COMMON_H
+#define OPENTRACING_C_WRAPPER_COMMON_H
+
+__CPLUSPLUS_DECL_BEGIN
+
+/***
+ * boolean type
+ */
+typedef enum {
+ otc_false = 0,
+ otc_true = 1,
+} otc_bool_t;
+
+/***
+ * duration type for calculating intervals (monotonic)
+ */
+struct otc_duration {
+ struct timespec value;
+};
+
+/***
+ * timestamp type for absolute time
+ */
+struct otc_timestamp {
+ struct timespec value;
+};
+
+__CPLUSPLUS_DECL_END
+#endif /* OPENTRACING_C_WRAPPER_COMMON_H */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/include/opentracing-c-wrapper/dbg_malloc.h b/include/opentracing-c-wrapper/dbg_malloc.h
new file mode 100644
index 0000000..4af56ca
--- /dev/null
+++ b/include/opentracing-c-wrapper/dbg_malloc.h
@@ -0,0 +1,86 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 OPENTRACING_C_WRAPPER_DBG_MALLOC_H
+#define OPENTRACING_C_WRAPPER_DBG_MALLOC_H
+
+__CPLUSPLUS_DECL_BEGIN
+
+#ifdef OTC_DBG_MEM
+
+#define OTC_DBG_MALLOC(s) otc_dbg_malloc(__func__, __LINE__, (s))
+#define OTC_DBG_CALLOC(n,e) otc_dbg_calloc(__func__, __LINE__, (n), (e))
+#define OTC_DBG_REALLOC(p,s) otc_dbg_realloc(__func__, __LINE__, (p), (s))
+#define OTC_DBG_FREE(p) otc_dbg_free(__func__, __LINE__, (p))
+#define OTC_DBG_STRDUP(s) otc_dbg_strdup(__func__, __LINE__, (s))
+#define OTC_DBG_STRNDUP(s,n) otc_dbg_strndup(__func__, __LINE__, (s), (n))
+#define OTC_DBG_MEMDUP(s,n) otc_dbg_memdup(__func__, __LINE__, (s), (n))
+#define OTC_DBG_MEMINFO() otc_dbg_mem_info()
+
+
+struct otc_dbg_mem_data {
+ const void *ptr;
+ size_t size;
+ char func[63];
+ bool used;
+} __attribute__((packed));
+
+struct otc_dbg_mem {
+ struct otc_dbg_mem_data *data;
+ size_t count;
+ size_t unused;
+ size_t reused;
+ uint64_t size;
+ uint64_t op_cnt[4];
+ uint8_t level;
+ pthread_mutex_t mutex;
+};
+
+
+void *otc_dbg_malloc(const char *func, int line, size_t size);
+void *otc_dbg_calloc(const char *func, int line, size_t nelem, size_t elsize);
+void *otc_dbg_realloc(const char *func, int line, void *ptr, size_t size);
+void otc_dbg_free(const char *func, int line, void *ptr);
+char *otc_dbg_strdup(const char *func, int line, const char *s);
+char *otc_dbg_strndup(const char *func, int line, const char *s, size_t size);
+void *otc_dbg_memdup(const char *func, int line, const void *s, size_t size);
+int otc_dbg_mem_init(struct otc_dbg_mem *mem, struct otc_dbg_mem_data *data, size_t count, uint8_t level);
+void otc_dbg_mem_disable(void);
+void otc_dbg_mem_info(void);
+
+#else
+
+#define OTC_DBG_MALLOC(s) malloc(s)
+#define OTC_DBG_CALLOC(n,e) calloc((n), (e))
+#define OTC_DBG_REALLOC(p,s) realloc((p), (s))
+#define OTC_DBG_FREE(p) free(p)
+#define OTC_DBG_STRDUP(s) strdup(s)
+#define OTC_DBG_STRNDUP(s,n) strndup((s), (n))
+#define OTC_DBG_MEMDUP(s,n) mem_dup((s), (n))
+#define OTC_DBG_MEMINFO() while (0)
+
+#endif /* OTC_DBG_MEM */
+
+__CPLUSPLUS_DECL_END
+#endif /* OPENTRACING_C_WRAPPER_DBG_MALLOC_H */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/include/opentracing-c-wrapper/define.h b/include/opentracing-c-wrapper/define.h
new file mode 100644
index 0000000..457e549
--- /dev/null
+++ b/include/opentracing-c-wrapper/define.h
@@ -0,0 +1,46 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 OPENTRACING_C_WRAPPER_DEFINE_H
+#define OPENTRACING_C_WRAPPER_DEFINE_H
+
+#define OTC_MAXLOGFIELDS 8
+
+#ifdef __cplusplus
+# define __CPLUSPLUS_DECL_BEGIN extern "C" {
+# define __CPLUSPLUS_DECL_END }
+#else
+# define __CPLUSPLUS_DECL_BEGIN
+# define __CPLUSPLUS_DECL_END
+#endif
+
+#ifdef __GNUC__
+# define OTC_NONNULL(...) __attribute__((nonnull(__VA_ARGS__)))
+# define OTC_NONNULL_ALL __attribute__((nonnull))
+#else
+# define OTC_NONNULL(...)
+# define OTC_NONNULL_ALL
+#endif
+
+#endif /* OPENTRACING_C_WRAPPER_DEFINE_H */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/include/opentracing-c-wrapper/include.h b/include/opentracing-c-wrapper/include.h
new file mode 100644
index 0000000..ac2f3e4
--- /dev/null
+++ b/include/opentracing-c-wrapper/include.h
@@ -0,0 +1,39 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 OPENTRACING_C_WRAPPER_INCLUDE_H
+#define OPENTRACING_C_WRAPPER_INCLUDE_H
+
+#include <stdbool.h>
+
+#include <opentracing-c-wrapper/define.h>
+#include <opentracing-c-wrapper/dbg_malloc.h>
+#include <opentracing-c-wrapper/common.h>
+#include <opentracing-c-wrapper/util.h>
+#include <opentracing-c-wrapper/value.h>
+#include <opentracing-c-wrapper/span.h>
+#include <opentracing-c-wrapper/propagation.h>
+#include <opentracing-c-wrapper/tracer.h>
+
+#endif /* OPENTRACING_C_WRAPPER_INCLUDE_H */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/include/opentracing-c-wrapper/propagation.h b/include/opentracing-c-wrapper/propagation.h
new file mode 100644
index 0000000..636ca37
--- /dev/null
+++ b/include/opentracing-c-wrapper/propagation.h
@@ -0,0 +1,201 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 OPENTRACING_C_WRAPPER_PROPAGATION_H
+#define OPENTRACING_C_WRAPPER_PROPAGATION_H
+
+__CPLUSPLUS_DECL_BEGIN
+
+/***
+ * span context propagation error codes
+ */
+typedef enum {
+ /***
+ * success
+ */
+ otc_propagation_error_code_success = 0,
+
+ /***
+ * not enough information to extract a span context
+ */
+ otc_propagation_error_code_span_context_not_found = -2,
+
+ /***
+ * invalid/incompatible span context
+ */
+ otc_propagation_error_code_invalid_span_context = -3,
+
+ /***
+ * invalid carrier
+ */
+ otc_propagation_error_code_invalid_carrier = -4,
+
+ /***
+ * corrupted carrier
+ */
+ otc_propagation_error_code_span_context_corrupted = -5,
+
+ /***
+ * unknown error
+ */
+ otc_propagation_error_code_unknown = -6,
+
+ /***
+ * tracer not initialized
+ */
+ otc_propagation_error_code_invalid_tracer = -7,
+
+} otc_propagation_error_code_t;
+
+
+/***
+ * Used to set information into a span context for propagation, entries
+ * are strings in a map of string pointers
+ *
+ * set and get implementations should use the same convention
+ * for naming the keys they manipulate
+ */
+struct otc_text_map_writer {
+ struct otc_text_map text_map;
+
+ /***
+ * NAME
+ * set -
+ *
+ * ARGUMENTS
+ * writer - writer instance
+ * key - string key
+ * value - string value
+ *
+ * DECRTIPTION
+ * set a key-value pair
+ *
+ * RETURN VALUE
+ * otc_propagation_error_code_t - indicates success or failure
+ */
+ otc_propagation_error_code_t (*set)(struct otc_text_map_writer *writer, const char *key, const char *value)
+ OTC_NONNULL(1);
+};
+
+/***
+ * Used to get information from a propagated span context
+ *
+ * set and get implementations should use the same convention
+ * for naming the keys they manipulate
+ */
+struct otc_text_map_reader {
+ struct otc_text_map text_map;
+
+ /***
+ * NAME
+ * foreach_key -
+ *
+ * ARGUMENTS
+ * reader - reader instance
+ * handler - handler function for each key-value pair
+ * arg - user-defined contents
+ *
+ * DESCRIPTION
+ * gets map entries by colling the handler function repeatedly. Returns immediately upon first error
+ *
+ * RETURN VALUE
+ * - error code indicating success or failure.
+ */
+ otc_propagation_error_code_t (*foreach_key)(struct otc_text_map_reader *reader, otc_propagation_error_code_t (*handler)(void *arg, const char *key, const char *value), void *arg)
+ OTC_NONNULL(1, 2);
+};
+
+/***
+ * Used to set HTTP headers
+ */
+struct otc_http_headers_writer {
+ struct otc_text_map text_map;
+
+ otc_propagation_error_code_t (*set)(struct otc_http_headers_writer *writer, const char *key, const char *value)
+ OTC_NONNULL(1);
+};
+
+/***
+ * USed to get HTTP headers
+ */
+struct otc_http_headers_reader {
+ struct otc_text_map text_map;
+
+ otc_propagation_error_code_t (*foreach_key)(struct otc_http_headers_reader *reader, otc_propagation_error_code_t (*handler)(void *arg, const char *key, const char *value), void *arg)
+ OTC_NONNULL(1, 2);
+};
+
+/***
+ * Set/write to a custom format
+ */
+struct otc_custom_carrier_writer {
+ struct otc_binary_data binary_data;
+
+ /***
+ * NAME
+ * inject -
+ *
+ * ARGUMENTS
+ * writer - writer instance
+ * tracer - tracer instance
+ * span_context - span context to write
+ * DESCRIPTION
+ * write a span context into a custom format
+ *
+ * RETURN VALUE
+ * - error code indicating success or failure
+ */
+ otc_propagation_error_code_t (*inject)(struct otc_custom_carrier_writer *writer, const struct otc_tracer *tracer, const struct otc_span_context *span_context)
+ OTC_NONNULL_ALL;
+};
+
+/***
+ * Get from a custom format
+ */
+struct otc_custom_carrier_reader {
+ struct otc_binary_data binary_data;
+
+ /***
+ * NAME
+ * extract -
+ *
+ * ARGUMENTS
+ * reader - reader instance
+ * tracer - tracer instance
+ * span_context - span context pointer to return the decoded
+ * span (can be NULL if propagation failed
+ * or OOM)
+ *
+ * DESCRIPTION
+ * - get a span context from a custom format
+ *
+ * RETURN VALUE
+ * - error code indicating success or failure
+ */
+ otc_propagation_error_code_t (*extract)(struct otc_custom_carrier_reader *reader, const struct otc_tracer *tracer, struct otc_span_context **span_context)
+ OTC_NONNULL_ALL;
+};
+
+__CPLUSPLUS_DECL_END
+#endif /* OPENTRACING_C_WRAPPER_PROPAGATION_H */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/include/opentracing-c-wrapper/span.h b/include/opentracing-c-wrapper/span.h
new file mode 100644
index 0000000..2ecf8b5
--- /dev/null
+++ b/include/opentracing-c-wrapper/span.h
@@ -0,0 +1,274 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 OPENTRACING_C_WRAPPER_SPAN_H
+#define OPENTRACING_C_WRAPPER_SPAN_H
+
+__CPLUSPLUS_DECL_BEGIN
+
+/***
+ * Encode a key-value for logging
+ */
+struct otc_log_field {
+ /***
+ * key string
+ */
+ const char *key;
+
+ /***
+ * representation of the value
+ */
+ struct otc_value value;
+};
+
+/***
+ * A log entry for events that occured during the span lifetime
+ */
+struct otc_log_record {
+ /***
+ * event timestamp
+ */
+ struct otc_timestamp timestamp;
+
+ /***
+ * array of log fields
+ */
+ struct otc_log_field *fields;
+
+ /***
+ * number of log fields, must be set to zero if fields is NULL
+ */
+ int num_fields;
+};
+
+typedef enum {
+ /***
+ * parent span that created and also depends on the child span
+ */
+ otc_span_reference_child_of = 1,
+
+ /***
+ * parent span that doesn't dpeend on the child span
+ *
+ * more details in http://opentracing.io/spec/
+ */
+ otc_span_reference_follows_from = 2
+} otc_span_reference_type_t;
+
+struct otc_span_reference {
+ otc_span_reference_type_t type;
+ struct otc_span_context *referenced_context;
+};
+
+struct otc_finish_span_options {
+ /***
+ * time when the span finished (monotonic clock)
+ */
+ struct otc_duration finish_time;
+
+ /***
+ * array with otc_log_record entries
+ */
+ const struct otc_log_record *log_records;
+
+ /***
+ * number of log records, must be set to zero if fields is NULL
+ */
+ int num_log_records;
+};
+
+/***
+ * The span interface
+ */
+struct otc_span {
+ int64_t idx;
+
+ /***
+ * NAME
+ * finish -
+ *
+ * ARGUMENTS
+ * span - span instance
+ *
+ * DESCRIPTION
+ * sets the ending timestamp and finalizes span. Must be the last call for a span instance (except calls to context)
+ */
+ void (*finish)(struct otc_span *span)
+ OTC_NONNULL_ALL;
+
+ /***
+ * NAME
+ * finish_with_options -
+ *
+ * ARGUMENTS
+ * span - span instance
+ * options - override span completion with these options
+ *
+ * DESCRIPTION
+ * finalizes the span but allows for customizing the timestamp and log data
+ */
+ void (*finish_with_options)(struct otc_span *span, const struct otc_finish_span_options *options)
+ OTC_NONNULL(1);
+
+ /***
+ * NAME
+ * otc_span_context -
+ *
+ * ARGUMENTS
+ * span - span instance
+ *
+ * DESCRIPTION
+ * returns an otc_span_context for the span
+ *
+ * RETURN VALUE
+ * span - context for this span
+ */
+ struct otc_span_context *(*span_context)(struct otc_span *span)
+ OTC_NONNULL_ALL;
+
+ /***
+ * NAME
+ * set_operation_name -
+ *
+ * ARGUMENTS
+ * span - span instance
+ * operation_name - new operation name
+ *
+ * DESCRIPTION
+ * set or change the operation name
+ */
+ void (*set_operation_name)(struct otc_span *span, const char *operation_name)
+ OTC_NONNULL_ALL;
+
+ /***
+ * NAME
+ * set_tag
+ *
+ * ARGUMENTS
+ * span - span instance
+ * key - tag key to copy into the span
+ * value - tag value to copy into the span
+ *
+ * DESCRIPTION
+ * add a tag to a span, overwriting any existing tag with the
+ * same key. Tag values supported are strings, numbers and bools
+ */
+ void (*set_tag)(struct otc_span *span, const char *key, const struct otc_value *value)
+ OTC_NONNULL_ALL;
+
+ /***
+ * NAME
+ * log_fields -
+ *
+ * ARGUMENTS
+ * span - span instance
+ * fields - log fields as an array, values should be copied by the implementation
+ * num_fields - number of log fields in the log field array
+ *
+ * DESCRIPTION
+ * store log data for a span
+ */
+ void (*log_fields)(struct otc_span *span, const struct otc_log_field *fields, int num_fields)
+ OTC_NONNULL(1);
+
+ /***
+ * NAME
+ * set_baggage_item -
+ *
+ * ARGUMENTS
+ * span - span instance
+ * key - baggage key
+ * value - baggage value
+ *
+ * DESCRIPTION
+ * store a key-value pair to this span and the associated span
+ * context, also propagating to descendents
+ */
+ void (*set_baggage_item)(struct otc_span *span, const char *key, const char *value)
+ OTC_NONNULL_ALL;
+
+ /***
+ * NAME
+ * baggage_item -
+ *
+ * ARGUMENTS
+ * span - span instance
+ * key - baggage key
+ *
+ * DESCRIPTION
+ * get the baggage for a baggage key
+ *
+ * RETURN VALUE
+ * baggage value for the key, or empty string if the key doesn't exist
+ */
+ const char *(*baggage_item)(const struct otc_span *span, const char *key)
+ OTC_NONNULL_ALL;
+
+ /***
+ * NAME
+ * tracer -
+ *
+ * ARGUMENTS
+ * span - span instance
+ *
+ * DESCRIPTION
+ * returns the tracer that created the span
+ *
+ * RETURN VALUE
+ * tracer instance that creaated the span
+ */
+ struct otc_tracer *(*tracer)(const struct otc_span *span)
+ OTC_NONNULL_ALL;
+
+ /***
+ * NAME
+ * destroy -
+ *
+ * ARGUMENTS
+ * span - span instance
+ */
+ void (*destroy)(struct otc_span **span)
+ OTC_NONNULL_ALL;
+};
+
+/***
+ * interface for span context
+ */
+struct otc_span_context {
+ int64_t idx;
+ const struct otc_span *span;
+
+ /***
+ * NAME
+ * destroy -
+ *
+ * ARGUMENTS
+ * context - instance of span context
+ */
+ void (*destroy)(struct otc_span_context **context)
+ OTC_NONNULL_ALL;
+};
+
+__CPLUSPLUS_DECL_END
+#endif /* OPENTRACING_C_WRAPPER_SPAN_H */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/include/opentracing-c-wrapper/tracer.h b/include/opentracing-c-wrapper/tracer.h
new file mode 100644
index 0000000..ca27e1e
--- /dev/null
+++ b/include/opentracing-c-wrapper/tracer.h
@@ -0,0 +1,93 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 OPENTRACING_C_WRAPPER_TRACER_H
+#define OPENTRACING_C_WRAPPER_TRACER_H
+
+__CPLUSPLUS_DECL_BEGIN
+
+struct otc_tag {
+ const char *key;
+ struct otc_value value;
+};
+
+struct otc_start_span_options {
+ struct otc_duration start_time_steady;
+ struct otc_timestamp start_time_system;
+ const struct otc_span_reference *references;
+ int num_references;
+ const struct otc_tag *tags;
+ int num_tags;
+};
+
+/***
+ * tracer interface
+ */
+struct otc_tracer {
+ void (*close)(struct otc_tracer *tracer)
+ OTC_NONNULL_ALL;
+
+ struct otc_span *(*start_span)(struct otc_tracer *tracer, const char *operation_name)
+ OTC_NONNULL_ALL;
+
+ struct otc_span *(*start_span_with_options)(struct otc_tracer *tracer, const char *operation_name, const struct otc_start_span_options *options)
+ OTC_NONNULL(1, 2);
+
+ otc_propagation_error_code_t (*inject_text_map)(struct otc_tracer *tracer, struct otc_text_map_writer *carrier, const struct otc_span_context *span_context)
+ OTC_NONNULL_ALL;
+
+ otc_propagation_error_code_t (*inject_http_headers)(struct otc_tracer *tracer, struct otc_http_headers_writer *carrier, const struct otc_span_context *span_context)
+ OTC_NONNULL_ALL;
+
+ otc_propagation_error_code_t (*inject_binary)(struct otc_tracer *tracer, struct otc_custom_carrier_writer *carrier, const struct otc_span_context *span_context)
+ OTC_NONNULL_ALL;
+
+ otc_propagation_error_code_t (*inject_custom)(struct otc_tracer *tracer, struct otc_custom_carrier_writer *carrier, const struct otc_span_context *span_context)
+ OTC_NONNULL_ALL;
+
+ otc_propagation_error_code_t (*extract_text_map)(struct otc_tracer *tracer, const struct otc_text_map_reader *carrier, struct otc_span_context **span_context)
+ OTC_NONNULL_ALL;
+
+ otc_propagation_error_code_t (*extract_http_headers)(struct otc_tracer *tracer, const struct otc_http_headers_reader *carrier, struct otc_span_context **span_context)
+ OTC_NONNULL_ALL;
+
+ otc_propagation_error_code_t (*extract_binary)(struct otc_tracer *tracer, const struct otc_custom_carrier_reader *carrier, struct otc_span_context **span_context)
+ OTC_NONNULL_ALL;
+
+ otc_propagation_error_code_t (*extract_custom)(struct otc_tracer *tracer, const struct otc_custom_carrier_reader *carrier, struct otc_span_context **span_context)
+ OTC_NONNULL_ALL;
+
+ void (*destroy)(struct otc_tracer **tracer)
+ OTC_NONNULL_ALL;
+};
+
+
+struct otc_tracer *otc_tracer_init(const char *library, const char *cfgfile, const char *cfgbuf, char *errbuf, int errbufsiz);
+struct otc_tracer *otc_tracer_load(const char *library, char *errbuf, int errbufsiz);
+int otc_tracer_start(const char *cfgfile, const char *cfgbuf, char *errbuf, int errbufsiz);
+void otc_tracer_global(struct otc_tracer *tracer);
+void otc_tracer_init_global(struct otc_tracer *tracer);
+
+__CPLUSPLUS_DECL_END
+#endif /* OPENTRACING_C_WRAPPER_TRACER_H */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/include/opentracing-c-wrapper/util.h b/include/opentracing-c-wrapper/util.h
new file mode 100644
index 0000000..c47c1e4
--- /dev/null
+++ b/include/opentracing-c-wrapper/util.h
@@ -0,0 +1,110 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 OPENTRACING_C_WRAPPER_UTIL_H
+#define OPENTRACING_C_WRAPPER_UTIL_H
+
+__CPLUSPLUS_DECL_BEGIN
+
+typedef enum {
+ OTC_TEXT_MAP_DUP_KEY = 0x01, /* Duplicate the key data. */
+ OTC_TEXT_MAP_DUP_VALUE = 0x02, /* Duplicate the value data. */
+ OTC_TEXT_MAP_FREE_KEY = 0x04, /* Release the key data. */
+ OTC_TEXT_MAP_FREE_VALUE = 0x08, /* Release the value data. */
+} otc_text_map_flags_t;
+
+struct otc_text_map {
+ char **key;
+ char **value;
+ size_t count;
+ size_t size;
+ bool is_dynamic;
+};
+
+struct otc_binary_data {
+ void *data;
+ size_t size;
+ bool is_dynamic;
+};
+
+/*
+ * Jaeger Trace/Span Identity
+ * uber-trace-id: {trace-id}:{span-id}:{parent-span-id}:{flags}
+ * uberctx-{baggage-key}: {value}
+ *
+ * Zipkin
+ * x-b3-traceid: {trace-id}
+ * x-b3-spanid: {span-id}
+ * x-b3-parentspanid: {parent-span-id}
+ * x-b3-flags: {flags}
+ * x-b3-sampled: {value}
+ * ot-baggage-{baggage-key}: {value}
+ *
+ * DataDog
+ * x-datadog-trace-id: {trace-id}
+ * x-datadog-parent-id: {parent-id}
+ * x-datadog-sampling-priority: {value}
+ * ot-baggage-{baggage-key}: {value}
+ */
+struct otc_jaeger_trace_context {
+ uint64_t trace_id[2]; /* 128-bit random number, value of 0 is not valid. */
+ uint64_t span_id; /* 64-bit random number, value of 0 is not valid. */
+ uint64_t parent_span_id; /* 64-bit parent span id, 0 value is valid and means 'root span' */
+ uint8_t flags; /* 8-bit bitmap, only bits 0 and 1 are used. */
+ uint8_t baggage[0];
+} __attribute__((packed));
+
+struct otc_zipkin_trace_context {
+ uint8_t data[0];
+} __attribute__((packed));
+
+struct otc_dd_trace_context {
+ uint8_t data[0];
+} __attribute__((packed));
+
+
+#ifdef OTC_DBG_MEM
+typedef void *(*otc_ext_malloc_t)(const char *, int, size_t);
+typedef void (*otc_ext_free_t)(const char *, int, void *);
+#else
+typedef void *(*otc_ext_malloc_t)(size_t);
+typedef void (*otc_ext_free_t)(void *);
+#endif
+
+
+void otc_ext_init(otc_ext_malloc_t func_malloc, otc_ext_free_t func_free);
+
+struct otc_text_map *otc_text_map_new(struct otc_text_map *text_map, size_t size);
+int otc_text_map_add(struct otc_text_map *text_map, const char *key, size_t key_len, const char *value, size_t value_len, otc_text_map_flags_t flags);
+void otc_text_map_destroy(struct otc_text_map **text_map, otc_text_map_flags_t flags);
+
+struct otc_binary_data *otc_binary_data_new(struct otc_binary_data *binary_data, const void *data, size_t size);
+void otc_binary_data_destroy(struct otc_binary_data **binary_data);
+
+char *otc_file_read(const char *filename, const char *comment, char *errbuf, int errbufsiz);
+
+void otc_statistics(char *buffer, size_t bufsiz);
+
+__CPLUSPLUS_DECL_END
+#endif /* OPENTRACING_C_WRAPPER_UTIL_H */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/include/opentracing-c-wrapper/value.h b/include/opentracing-c-wrapper/value.h
new file mode 100644
index 0000000..b9a55fd
--- /dev/null
+++ b/include/opentracing-c-wrapper/value.h
@@ -0,0 +1,60 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 OPENTRACING_C_WRAPPER_VALUE_H
+#define OPENTRACING_C_WRAPPER_VALUE_H
+
+__CPLUSPLUS_DECL_BEGIN
+
+/***
+ * value types
+ */
+typedef enum {
+ otc_value_bool = 0,
+ otc_value_double,
+ otc_value_int64,
+ otc_value_uint64,
+ otc_value_string,
+ otc_value_null,
+} otc_value_type_t;
+
+
+/***
+ * union for representing various value types
+ */
+struct otc_value {
+
+ otc_value_type_t type;
+
+ union {
+ otc_bool_t bool_value;
+ double double_value;
+ int64_t int64_value;
+ uint64_t uint64_value;
+ const char *string_value;
+ } value;
+};
+
+__CPLUSPLUS_DECL_END
+#endif /* OPENTRACING_C_WRAPPER_VALUE_H */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/include/span.h b/include/span.h
new file mode 100644
index 0000000..14c0b6c
--- /dev/null
+++ b/include/span.h
@@ -0,0 +1,94 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 _OPENTRACING_C_WRAPPER_SPAN_H_
+#define _OPENTRACING_C_WRAPPER_SPAN_H_
+
+#define OT_LF(a) { fields[a].key, str_value[a] }
+
+
+class otc_hash {
+ public:
+ size_t operator() (int64_t key) const { return key; }
+};
+
+
+class otc_equal_to {
+ public:
+ bool operator() (int64_t a, int64_t b) const { return a == b; }
+};
+
+
+# ifdef OT_THREADS_NO_LOCKING
+template<typename T>
+ using Handle = std::unordered_map<
+ int64_t,
+ std::unique_ptr<T>,
+ otc_hash,
+ otc_equal_to
+ >;
+struct HandleData {
+ int64_t key;
+ int64_t alloc_fail_cnt;
+ int64_t erase_cnt;
+ int64_t destroy_cnt;
+};
+
+# define OT_LOCK_GUARD(a,...)
+# define OT_LOCK(a,b)
+
+extern thread_local Handle<opentracing::Span> ot_span_handle;
+extern thread_local Handle<opentracing::SpanContext> ot_span_context_handle;
+extern struct HandleData ot_span;
+extern struct HandleData ot_span_context;
+# else
+template<typename T> struct Handle {
+ std::unordered_map<
+ int64_t,
+ std::unique_ptr<T>,
+ otc_hash,
+ otc_equal_to
+ > handle;
+ int64_t key;
+ int64_t alloc_fail_cnt;
+ int64_t erase_cnt;
+ int64_t destroy_cnt;
+ std::mutex mutex;
+};
+
+# define ot_span_handle ot_span.handle
+# define ot_span_context_handle ot_span_context.handle
+# define OT_LOCK_GUARD(a,...) const std::lock_guard<std::mutex> guard_##a(ot_##a.mutex, ##__VA_ARGS__)
+# define OT_LOCK(a,b) std::lock(ot_##a.mutex, ot_##b.mutex); OT_LOCK_GUARD(a, std::adopt_lock); OT_LOCK_GUARD(b, std::adopt_lock);
+
+extern struct Handle<opentracing::Span> ot_span;
+extern struct Handle<opentracing::SpanContext> ot_span_context;
+# endif /* OT_THREADS_NO_LOCKING */
+
+
+struct otc_span *ot_span_new(void);
+void ot_nolock_span_destroy(struct otc_span **span);
+struct otc_span_context *ot_span_context_new(const struct otc_span *span);
+
+#endif /* _OPENTRACING_C_WRAPPER_SPAN_H_ */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/include/tracer.h b/include/tracer.h
new file mode 100644
index 0000000..371f2b5
--- /dev/null
+++ b/include/tracer.h
@@ -0,0 +1,133 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 _OPENTRACING_C_WRAPPER_TRACER_H_
+#define _OPENTRACING_C_WRAPPER_TRACER_H_
+
+using TextMap = std::unordered_map<std::string, std::string>;
+
+
+class TextMapCarrier : public opentracing::TextMapReader, public opentracing::TextMapWriter {
+ public:
+ TextMapCarrier(TextMap &text_map) : tm_data(text_map) {}
+
+ /***
+ * TextMapWriter: Set a key:value pair to the carrier. Multiple calls
+ * to Set() for the same key leads to undefined behavior.
+ */
+ opentracing::expected<void> Set(opentracing::string_view key, opentracing::string_view value) const override
+ {
+ tm_data[key] = value;
+
+ return {};
+ }
+
+ /***
+ * TextMapReader: LookupKey() returns the value for the specified
+ * key if available. If no such key is present, it returns
+ * key_not_found_error.
+ */
+ opentracing::expected<opentracing::string_view> LookupKey(opentracing::string_view key) const override
+ {
+ auto iter = tm_data.find(key);
+ if (iter != tm_data.end())
+ return opentracing::string_view{iter->second};
+
+ return opentracing::make_unexpected(opentracing::key_not_found_error);
+ }
+
+ /***
+ * TextMapReader: ForeachKey() returns TextMap contents via repeated
+ * calls to the f() function. If any call to f() returns an error,
+ * ForeachKey() terminates and returns that error.
+ */
+ opentracing::expected<void> ForeachKey(std::function<opentracing::expected<void>(opentracing::string_view key, opentracing::string_view value)> f) const override
+ {
+ for (const auto &text_map : tm_data) {
+ auto result = f(text_map.first, text_map.second);
+ if (!result)
+ return result;
+ }
+
+ return {};
+ }
+
+ private:
+ TextMap &tm_data;
+};
+
+
+class HTTPHeadersCarrier : public opentracing::HTTPHeadersReader, public opentracing::HTTPHeadersWriter {
+ public:
+ HTTPHeadersCarrier(TextMap &text_map) : tm_data(text_map) {}
+
+ /***
+ * HTTPHeadersWriter: Set a key:value pair to the carrier. Multiple calls
+ * to Set() for the same key leads to undefined behavior.
+ */
+ opentracing::expected<void> Set(opentracing::string_view key, opentracing::string_view value) const override
+ {
+ tm_data[key] = value;
+
+ return {};
+ }
+
+ /***
+ * HTTPHeadersReader: LookupKey() returns the value for the specified
+ * key if available. If no such key is present, it returns
+ * key_not_found_error.
+ */
+ opentracing::expected<opentracing::string_view> LookupKey(opentracing::string_view key) const override
+ {
+ auto iter = tm_data.find(key);
+ if (iter != tm_data.end())
+ return opentracing::string_view{iter->second};
+
+ return opentracing::make_unexpected(opentracing::key_not_found_error);
+ }
+
+ /***
+ * HTTPHeadersReader: ForeachKey() returns TextMap contents via repeated
+ * calls to the f() function. If any call to f() returns an error,
+ * ForeachKey() terminates and returns that error.
+ */
+ opentracing::expected<void> ForeachKey(std::function<opentracing::expected<void>(opentracing::string_view key, opentracing::string_view value)> f) const override
+ {
+ for (const auto &text_map : tm_data) {
+ auto result = f(text_map.first, text_map.second);
+ if (!result)
+ return result;
+ }
+
+ return {};
+ }
+
+ private:
+ TextMap &tm_data;
+};
+
+
+struct otc_tracer *ot_tracer_new(void);
+
+#endif /* _OPENTRACING_C_WRAPPER_TRACER_H_ */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/include/util.h b/include/util.h
new file mode 100644
index 0000000..50a4109
--- /dev/null
+++ b/include/util.h
@@ -0,0 +1,46 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 _OPENTRACING_C_WRAPPER_UTIL_H_
+#define _OPENTRACING_C_WRAPPER_UTIL_H_
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+/* Parameter 'p' must not be in parentheses! */
+#define OT_TEXT_MAP_SIZE(p,n) (sizeof(text_map->p) * (text_map->size + (n)))
+
+
+extern otc_ext_malloc_t otc_ext_malloc;
+extern otc_ext_free_t otc_ext_free;
+
+
+std::chrono::microseconds timespec_to_duration_us(const struct timespec *ts);
+std::chrono::nanoseconds timespec_to_duration(const struct timespec *ts);
+const char *otc_strerror(int errnum);
+
+#endif /* _OPENTRACING_C_WRAPPER_UTIL_H_ */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/include/version.h.in b/include/version.h.in
new file mode 100644
index 0000000..ea00000
--- /dev/null
+++ b/include/version.h.in
@@ -0,0 +1,19 @@
+#ifndef _OPENTRACING_C_WRAPPER_VERSION_H_
+#define _OPENTRACING_C_WRAPPER_VERSION_H_
+
+#define PACKAGE_AUTHOR "Miroslav Zagorac <mzagorac@haproxy.com>"
+#define PACKAGE_CPP_FLAGS "@CPPFLAGS@"
+#define PACKAGE_DEFS "@DEFS@"
+#define PACKAGE_C_FLAGS "@CFLAGS@"
+#define PACKAGE_CONFIGURE_OPTIONS "@CONFIGURE_OPTIONS@"
+
+#endif /* _OPENTRACING_C_WRAPPER_VERSION_H_ */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/m4/am-common.m4 b/m4/am-common.m4
new file mode 100644
index 0000000..11c310b
--- /dev/null
+++ b/m4/am-common.m4
@@ -0,0 +1,375 @@
+dnl am-common.m4 by Miroslav Zagorac <mzagorac@haproxy.com>
+dnl
+AC_DEFUN([AX_TYPE_BOOL_T], [AC_CHECK_TYPE([bool_t], [unsigned char])])
+AC_DEFUN([AX_TYPE_UNCHAR], [AC_CHECK_TYPE([unchar], [unsigned char])])
+AC_DEFUN([AX_TYPE_USHORT], [AC_CHECK_TYPE([ushort], [unsigned short])])
+AC_DEFUN([AX_TYPE_ULONG], [AC_CHECK_TYPE([ulong], [unsigned long])])
+AC_DEFUN([AX_TYPE_UINT], [AC_CHECK_TYPE([uint], [unsigned int])])
+
+AC_DEFUN([AX_VARIABLES_STORE], [
+ _saved_cppflags="${CPPFLAGS}"
+ _saved_cflags="${CFLAGS}"
+ _saved_cxxflags="${CXXFLAGS}"
+ _saved_ldflags="${LDFLAGS}"
+ _saved_libs="${LIBS}"
+])
+
+AC_DEFUN([AX_VARIABLES_RESTORE], [
+ CPPFLAGS="${_saved_cppflags}"
+ CFLAGS="${_saved_cflags}"
+ CXXFLAGS="${_saved_cxxflags}"
+ LDFLAGS="${_saved_ldflags}"
+ LIBS="${_saved_libs}"
+])
+
+AC_DEFUN([AX_VARIABLES_INIT], [
+ SET_CPPFLAGS=
+ SET_CFLAGS=
+ SET_CXXFLAGS=
+ SET_LDFLAGS=
+ SET_LIBS=
+])
+
+AC_DEFUN([AX_VARIABLES_SET], [
+ CPPFLAGS="${CPPFLAGS} ${SET_CPPFLAGS}"
+ CFLAGS="${CFLAGS} ${SET_CFLAGS}"
+ CXXFLAGS="${CXXFLAGS} ${SET_CXXFLAGS}"
+ LDFLAGS="${LDFLAGS} ${SET_LDFLAGS}"
+ LIBS="${LIBS} ${SET_LIBS}"
+])
+
+dnl Check which options the C compiler supports.
+dnl
+AC_DEFUN([AX_PROG_CC_SET], [
+ _var_cflags=
+ _loop_cflags=
+
+ AX_VARIABLES_STORE
+
+ case "${CC}" in
+ *gcc*)
+ _var_cflags="\
+ -Wall \
+ -Wextra \
+ -Waggregate-return \
+ -Wbad-function-cast \
+ -Wcast-align \
+ -Wchar-subscripts \
+ -Wcomment \
+ -Wfloat-equal \
+ -Wimplicit \
+ -Winline \
+ -Wmain \
+ -Wmissing-braces \
+ -Wmissing-declarations \
+ -Wmissing-noreturn \
+ -Wmissing-prototypes \
+ -Wnested-externs \
+ -Wparentheses \
+ -Wpointer-arith \
+ -Wreturn-type \
+ -Wsequence-point \
+ -Wshadow \
+ -Wstrict-prototypes \
+ -Wswitch \
+ -Wtrigraphs \
+ -Wundef \
+ -Wuninitialized \
+ -Wunused \
+ -Wwrite-strings"
+ if test "${enable_debug}" = "yes"; then
+ _var_cflags="${_var_cflags} \
+ -Wformat=2"
+ else
+ _var_cflags="${_var_cflags} \
+ -Wformat-security \
+ -Wformat-y2k"
+ fi
+ ;;
+ cc|clang)
+ case "${host_os}" in
+ *solaris*)
+ _var_cflags="-xCC"
+ ;;
+ *freebsd1?.*)
+ _var_cflags=
+ ;;
+ esac
+ ;;
+ esac
+
+ TMP_CFLAGS="${CFLAGS}"
+ AC_LANG_PUSH([C])
+ for _loop_cflags in ${_var_cflags} $1; do
+ AC_MSG_CHECKING([whether ${CC} accepts ${_loop_cflags}])
+ CFLAGS="${TMP_CFLAGS} ${_loop_cflags}"
+ AC_TRY_COMPILE([], [],
+ [AC_MSG_RESULT([ yes])
+ SET_CFLAGS="${SET_CFLAGS} ${_loop_cflags}"],
+ [AC_MSG_RESULT([ no])]
+ )
+ done
+ AC_LANG_POP([C])
+ CFLAGS="${TMP_CFLAGS}"
+
+ AX_VARIABLES_RESTORE
+])
+
+dnl Check which options the C++ compiler supports.
+dnl
+AC_DEFUN([AX_PROG_CXX_SET], [
+ _var_cxxflags=
+ _loop_cxxflags=
+
+ AX_VARIABLES_STORE
+
+ case "${CXX}" in
+ c++|clang++)
+ case "${host_os}" in
+ *freebsd1?.*)
+ _var_cxxflags="-Wno-extern-c-compat"
+ ;;
+ esac
+ ;;
+ *g++*)
+ _var_cxxflags="\
+ -Wall \
+ -Wextra \
+ -Wcast-align \
+ -Wchar-subscripts \
+ -Wcomment \
+ -Wfloat-equal \
+ -Winline \
+ -Wmain \
+ -Wmissing-braces \
+ -Wmissing-declarations \
+ -Wmissing-noreturn \
+ -Wparentheses \
+ -Wpointer-arith \
+ -Wreturn-type \
+ -Wsequence-point \
+ -Wshadow \
+ -Wswitch \
+ -Wtrigraphs \
+ -Wundef \
+ -Wuninitialized \
+ -Wunused \
+ -Wwrite-strings \
+ \
+ -Wconditionally-supported \
+ -Wnamespaces \
+ -Wno-invalid-offsetof \
+ -Wno-terminate \
+ -Wnoexcept \
+ -Wold-style-cast \
+ -Woverloaded-virtual \
+ -Wsign-promo \
+ -Wsized-deallocation \
+ -Wstrict-null-sentinel \
+ -Wuseless-cast \
+ -Wvirtual-inheritance \
+ -Wzero-as-null-pointer-constant"
+ if test "${enable_debug}" = "yes"; then
+ _var_cxxflags="${_var_cxxflags} \
+ -Waggregate-return \
+ -Wformat=2 \
+ -Wmultiple-inheritance \
+ -Wtemplates"
+ else
+ _var_cxxflags="${_var_cxxflags} \
+ -Wformat-security \
+ -Wformat-y2k"
+ fi
+ ;;
+ CC)
+ case "${host_os}" in
+ *solaris*)
+ _var_cxxflags=
+ ;;
+ esac
+ ;;
+ esac
+
+ TMP_CXXFLAGS="${CXXFLAGS}"
+ AC_LANG_PUSH([C++])
+ for _loop_cxxflags in ${_var_cxxflags} $1; do
+ AC_MSG_CHECKING([whether ${CXX} accepts ${_loop_cxxflags}])
+ CXXFLAGS="${TMP_CXXFLAGS} ${_loop_cxxflags}"
+ AC_TRY_COMPILE([], [],
+ [AC_MSG_RESULT([ yes])
+ SET_CXXFLAGS="${SET_CXXFLAGS} ${_loop_cxxflags}"],
+ [AC_MSG_RESULT([ no])]
+ )
+ done
+ AC_LANG_POP([C++])
+ CXXFLAGS="${TMP_CXXFLAGS}"
+
+ AX_VARIABLES_RESTORE
+])
+
+dnl Check whether the C++ compiler has noexcept specifier.
+dnl
+AC_DEFUN([AX_CHECK_NOEXCEPT], [
+ AC_MSG_CHECKING([whether the C++ compiler (${CXX}) has noexcept specifier])
+ AC_LANG_PUSH([C++])
+ AC_TRY_COMPILE([],
+ [void (*fp)() noexcept(false);],
+ [AC_MSG_RESULT([ yes])],
+ [CXXFLAGS="-std=gnu++11"
+ AC_MSG_RESULT([ no])]
+ )
+ AC_LANG_POP([C++])
+])
+
+dnl Check whether the C compiler has __DATE__ macro.
+dnl
+AC_DEFUN([AX_CHECK___DATE__], [
+ AC_MSG_CHECKING([whether the C compiler (${CC}) has __DATE__ macro])
+ AC_TRY_COMPILE([],
+ [char *test=__DATE__;],
+ [AC_MSG_RESULT([ yes])],
+ [AC_DEFINE_UNQUOTED([__DATE__], ["`date`"], [Define if your C compiled doesn't have __DATE__ macro.])
+ AC_MSG_RESULT([ no])]
+ )
+])
+
+dnl Check whether the C compiler has __func__ variable.
+dnl
+AC_DEFUN([AX_CHECK___FUNC__], [
+ AC_MSG_CHECKING([whether the C compiler (${CC}) has __func__ variable])
+ AC_TRY_COMPILE([#include <stdio.h>],
+ [printf ("%s", __func__);],
+ [AC_MSG_RESULT([ yes])],
+ [AC_DEFINE_UNQUOTED([__func__], ["__unknown__"], [Define if your C compiler doesn't have __func__ variable.])
+ AC_MSG_RESULT([ no])]
+ )
+])
+
+dnl Check whether the C compiler defines __STDC__.
+dnl
+AC_DEFUN([AX_CHECK___STDC__], [
+ AC_MSG_CHECKING([whether the C compiler (${CC}) defines __STDC__])
+ AC_TRY_COMPILE([],
+ [#ifndef __STDC__
+ test_stdc ();
+ #endif],
+ [AC_MSG_RESULT([ yes])
+ AC_DEFINE_UNQUOTED([ANSI_FUNC], [1], [Define if you use an ANSI C compiler.])
+ stdc_defined="yes"],
+ [AC_MSG_RESULT([ no])]
+ )
+])
+
+dnl
+dnl
+AC_DEFUN([AX_PROG_PKGCONFIG], [
+ AC_CHECK_PROG(PKG_CONFIG, [pkg-config], [yes], [no], [], [])
+ test "${PKG_CONFIG}" = "no" && AC_MSG_ERROR([pkg-config not found])
+])
+
+dnl
+dnl
+AC_DEFUN([AX_PATH_PKGCONFIG], [
+ PKG_CONFIG_PATH=
+ _pc_prefix="${ac_default_prefix}"
+ # ovdje se ne smije zamijeniti $n sa ${n} jer su to argumenti m4 funkcije AX_PATH_PKGCONFIG
+ test "$1" = "yes" -o "$1" = "check" || _pc_prefix="$1"
+
+ for _loop_path in \
+ ${_pc_prefix}/lib \
+ ${_pc_prefix}/lib/i386-linux-gnu \
+ ${_pc_prefix}/lib/x86_64-linux-gnu \
+ ${_pc_prefix}/amd64 \
+ ${_pc_prefix}/lib32 \
+ ${_pc_prefix}/lib64 \
+ ${_pc_prefix}/share
+ do
+ test -d "${_loop_path}/pkgconfig" && \
+ PKG_CONFIG_PATH="${PKG_CONFIG_PATH}${PKG_CONFIG_PATH:+:}${_loop_path}/pkgconfig"
+ done
+ AC_MSG_NOTICE([PKG_CONFIG_PATH=${PKG_CONFIG_PATH}])
+])
+
+dnl Check whether the C compiler has __attribute__ keyword.
+dnl
+AC_DEFUN([AX_CHECK___ATTRIBUTE__], [
+ AC_MSG_CHECKING([whether the C compiler (${CC}) has __attribute__ keyword])
+ AC_TRY_COMPILE([void t1 () __attribute__ ((noreturn)); void t1 () { return; };],
+ [t1 ();],
+ [AC_MSG_RESULT([ yes])
+ AC_DEFINE_UNQUOTED([__ATTRIBUTE__], [1], [Define if your C compiler has __attribute__ keyword.])],
+ [AC_MSG_RESULT([ no])]
+ )
+])
+
+AC_DEFUN([AX_ENABLE_DEBUG], [
+ AC_ARG_ENABLE([debug],
+ [AS_HELP_STRING([--enable-debug], [compile with debugging symbols/functions])],
+ [if test "${enableval}" = "yes"; then
+ AC_DEFINE([DEBUG], [1], [Define to 1 if you want to include debugging options.])
+ CFLAGS="${CFLAGS} -g -O0"
+ CXXFLAGS="${CXXFLAGS} -g -O0"
+ fi]
+ )
+])
+
+AC_DEFUN([AX_ENABLE_GPROF], [
+ AC_ARG_ENABLE([gprof],
+ [AS_HELP_STRING([--enable-gprof], [enable profiling with gprof])],
+ [if test "${enableval}" = "yes"; then
+ AC_DEFINE([GPROF], [1], [Define to 1 if you want to enable profiling with gprof.])
+ CFLAGS="${CFLAGS} -pg"
+ CXXFLAGS="${CXXFLAGS} -pg"
+ LDFLAGS="${LDFLAGS} -pg"
+ fi]
+ )
+])
+
+AC_DEFUN([AX_VARIABLE_SET], [
+_am_cache_test ()
+{
+ _c=
+
+ if test -n "${2}"; then
+ for _c in ${2}; do test "${_c}" = "${3}" && return 1; done
+ eval "${1}=\"${2} ${3}\""
+ else
+ eval "${1}=\"${3}\""
+ fi
+}
+
+ _am_var_resolved=
+ # ovdje se ne smije zamijeniti $n sa ${n} jer su to argumenti m4 funkcije AX_VARIABLE_SET
+ for _am_var_loop in $2; do
+ _am_cache_test _am_var_resolved "${_am_var_resolved}" "${_am_var_loop}"
+ done
+ $1=${_am_var_resolved}
+])
+
+AC_DEFUN([AX_SHOW_CONFIG], [
+ eval "bindir=${bindir}"
+ eval "datadir=${datadir}"
+ eval "sysconfdir=${sysconfdir}"
+ eval "mandir=${mandir}"
+
+ echo
+ echo "${PACKAGE_NAME} configuration:"
+ echo "--------------------------------------------------"
+ echo " package version : ${PACKAGE_VERSION}"
+ echo " library version : ${LIB_VERSION}"
+ echo " host operating system : ${host}"
+ echo " source code location : ${srcdir}"
+ echo " C compiler : ${CC}"
+ echo " C++ compiler : ${CXX}"
+ echo " preprocessor flags : ${CPPFLAGS}"
+ echo " C compiler flags : ${CFLAGS}"
+ echo " C++ compiler flags : ${CXXFLAGS}"
+ echo " linker flags : ${LDFLAGS}"
+ echo " libraries : ${LIBS}"
+ echo " configure options : ${ac_configure_args}"
+ echo " binary install path : ${bindir}"
+ echo " data install path : ${datadir}"
+ echo " configuration file path : ${sysconfdir}"
+ echo " man page install path : ${mandir}"
+ echo
+])
diff --git a/m4/am-enable-threads.m4 b/m4/am-enable-threads.m4
new file mode 100644
index 0000000..629325f
--- /dev/null
+++ b/m4/am-enable-threads.m4
@@ -0,0 +1,44 @@
+dnl am-enable-threads.m4 by Miroslav Zagorac <mzagorac@haproxy.com>
+dnl
+AC_DEFUN([AX_ENABLE_THREADS], [
+ AC_ARG_ENABLE([threads],
+ [AS_HELP_STRING([--enable-threads], [enable threads @<:@default=yes@:>@])],
+ [enable_threads="${enableval}"],
+ [enable_threads=yes]
+ )
+
+ if test "${enable_threads}" != "no"; then
+ HAVE_THREADS=
+ THREADS_CFLAGS=
+ THREADS_CPPFLAGS=
+ THREADS_LDFLAGS=
+ THREADS_LIBS=
+
+ AX_VARIABLES_STORE
+
+ LDFLAGS="${LDFLAGS} ${THREADS_LDFLAGS}"
+ CPPFLAGS="${CPPFLAGS} ${THREADS_CPPFLAGS}"
+
+ AC_CHECK_LIB([pthread], [pthread_create], [], [AC_MSG_ERROR([THREADS library not found])])
+ AC_CHECK_HEADER([pthread.h], [], [AC_MSG_ERROR([THREADS library headers not found])])
+
+ HAVE_THREADS=yes
+ THREADS_LIBS="-lpthread"
+
+ AC_DEFINE([USE_THREADS], [1], [Define to 1 for multi-thread support.])
+ AC_DEFINE([_REENTRANT], [1], [Define to 1 for multi-thread support.])
+
+ AX_VARIABLES_RESTORE
+
+ AC_MSG_NOTICE([THREADS environment variables:])
+ AC_MSG_NOTICE([ THREADS_CFLAGS=${THREADS_CFLAGS}])
+ AC_MSG_NOTICE([ THREADS_CPPFLAGS=${THREADS_CPPFLAGS}])
+ AC_MSG_NOTICE([ THREADS_LDFLAGS=${THREADS_LDFLAGS}])
+ AC_MSG_NOTICE([ THREADS_LIBS=${THREADS_LIBS}])
+
+ AC_SUBST([THREADS_CFLAGS])
+ AC_SUBST([THREADS_CPPFLAGS])
+ AC_SUBST([THREADS_LDFLAGS])
+ AC_SUBST([THREADS_LIBS])
+ fi
+])
diff --git a/m4/am-host.m4 b/m4/am-host.m4
new file mode 100644
index 0000000..07d6353
--- /dev/null
+++ b/m4/am-host.m4
@@ -0,0 +1,44 @@
+dnl am-host.m4 by Miroslav Zagorac <mzagorac@haproxy.com>
+dnl
+AC_DEFUN([AX_HOST], [
+ dnl Get current date and time.
+ dnl
+ DATE=`date`
+
+ dnl Get cannonical host.
+ dnl
+ AC_CANONICAL_HOST
+ AC_DEFINE_UNQUOTED([OSTYPE], ["${host}"], [Guessed OS type.])
+
+ dnl Posix variants
+ dnl
+ AC_USE_SYSTEM_EXTENSIONS
+
+ dnl because ${${host_os%-*}##*-} does not work on stupid bash...
+ dnl
+ _host_os=${host_os%-*}
+ _host_os=${_host_os##*-}
+
+ case "${host_os}" in
+ *osf*)
+ test "${stdc_defined}" = "yes" || \
+ AC_DEFINE([__STDC__], [1], [Define to 1 if you use ANSI C compiler.])
+ AC_DEFINE([_REENTRANT], [1], [Define to 1 only for OSF Unix.])
+ AC_DEFINE([ANSI_FUNC], [1], [Define to 1 if you use ANSI C compiler.])
+ AC_DEFINE([OSF], [1], [Define to 1 for OSF Unix.])
+ ;;
+
+ *solaris*)
+ AC_DEFINE([ANSI_FUNC], [1], [Define to 1 if you use ANSI C compiler.])
+ AC_DEFINE([SOLARIS], [1], [Define to 1 for Solaris UNIX system.])
+ ;;
+
+ *sunos*)
+ AC_DEFINE([SUNOS], [1], [Define to 1 for SUNOS UNIX system.])
+ ;;
+
+ *linux*)
+ AC_DEFINE([LINUX], [1], [Define to 1 for Linux system.])
+ ;;
+ esac
+])
diff --git a/m4/am-with-opentracing.m4 b/m4/am-with-opentracing.m4
new file mode 100644
index 0000000..3bdb5ee
--- /dev/null
+++ b/m4/am-with-opentracing.m4
@@ -0,0 +1,71 @@
+dnl am-with-opentracing.m4 by Miroslav Zagorac <mzagorac@haproxy.com>
+dnl
+AC_DEFUN([AX_WITH_OPENTRACING], [
+ AC_ARG_WITH([opentracing],
+ [AS_HELP_STRING([--with-opentracing@<:@=DIR@:>@], [use OPENTRACING library @<:@default=yes@:>@])],
+ [with_opentracing="${withval}"],
+ [with_opentracing=yes]
+ )
+
+ AX_CHECK_NOEXCEPT([])
+
+ if test "${with_opentracing}" != "no"; then
+ HAVE_OPENTRACING=
+ OPENTRACING_CFLAGS=
+ OPENTRACING_CXXFLAGS=
+ OPENTRACING_CPPFLAGS=
+ OPENTRACING_LDFLAGS=
+ OPENTRACING_LIBS="-lopentracing"
+
+ if test -n "${with_opentracing}" -a "${with_opentracing}" != "yes" -a "${with_opentracing}" != "yes"; then
+ OPENTRACING_CPPFLAGS="-I${with_opentracing}/include"
+
+ if test "${with_opentracing}" != "/usr"; then
+ if test "`uname`" = "Linux"; then
+ OPENTRACING_LDFLAGS="-L${with_opentracing}/lib -Wl,--rpath,${with_opentracing}/lib"
+ elif test "`uname`" = "FreeBSD"; then
+ OPENTRACING_LDFLAGS="-L${with_opentracing}/lib -Wl,-rpath -Wl,${with_opentracing}/lib"
+ else
+ OPENTRACING_LDFLAGS="-L${with_opentracing}/lib -R${with_opentracing}/lib"
+ fi
+ fi
+ fi
+
+ AX_VARIABLES_STORE
+
+ LIBS="${LDFLAGS} ${OPENTRACING_LIBS}"
+ LDFLAGS="${LDFLAGS} ${OPENTRACING_LDFLAGS}"
+ CFLAGS="${CFLAGS} ${OPENTRACING_CFLAGS}"
+ CXXFLAGS="${CXXFLAGS} ${OPENTRACING_CXXFLAGS}"
+ CPPFLAGS="${CPPFLAGS} ${OPENTRACING_CPPFLAGS}"
+
+ AC_LANG_PUSH([C++])
+ AC_LINK_IFELSE([
+ AC_LANG_PROGRAM(
+ [[#include <opentracing/dynamic_load.h>]],
+ [[std::string e;] [auto a = opentracing::DynamicallyLoadTracingLibrary("", e);]]
+ )],
+ [],
+ [AC_MSG_ERROR([OPENTRACING library not found])]
+ )
+ AC_CHECK_HEADER([opentracing/version.h], [], [AC_MSG_ERROR([OPENTRACING library headers not found])])
+ AC_LANG_POP([C++])
+
+ HAVE_OPENTRACING=yes
+
+ AX_VARIABLES_RESTORE
+
+ AC_MSG_NOTICE([OPENTRACING environment variables:])
+ AC_MSG_NOTICE([ OPENTRACING_CFLAGS=${OPENTRACING_CFLAGS}])
+ AC_MSG_NOTICE([ OPENTRACING_CXXFLAGS=${OPENTRACING_CXXFLAGS}])
+ AC_MSG_NOTICE([ OPENTRACING_CPPFLAGS=${OPENTRACING_CPPFLAGS}])
+ AC_MSG_NOTICE([ OPENTRACING_LDFLAGS=${OPENTRACING_LDFLAGS}])
+ AC_MSG_NOTICE([ OPENTRACING_LIBS=${OPENTRACING_LIBS}])
+
+ AC_SUBST([OPENTRACING_CFLAGS])
+ AC_SUBST([OPENTRACING_CXXFLAGS])
+ AC_SUBST([OPENTRACING_CPPFLAGS])
+ AC_SUBST([OPENTRACING_LDFLAGS])
+ AC_SUBST([OPENTRACING_LIBS])
+ fi
+])
diff --git a/opentracing-c-wrapper.pc.in b/opentracing-c-wrapper.pc.in
new file mode 100644
index 0000000..f1a7f43
--- /dev/null
+++ b/opentracing-c-wrapper.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: opentracing-c-wrapper
+Description: The OpenTracing C wrapper library.
+Version: @VERSION@
+
+Requires:
+Libs: -L${libdir} -Wl,--rpath,${libdir} -lopentracing-c-wrapper
+Cflags: -I${includedir}
diff --git a/opentracing-c-wrapper_dbg.pc.in b/opentracing-c-wrapper_dbg.pc.in
new file mode 100644
index 0000000..5d0e4b9
--- /dev/null
+++ b/opentracing-c-wrapper_dbg.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: opentracing-c-wrapper_dbg
+Description: The OpenTracing C wrapper library with debugging support enabled.
+Version: @VERSION@
+
+Requires:
+Libs: -L${libdir} -Wl,--rpath,${libdir} -lopentracing-c-wrapper_dbg
+Cflags: -I${includedir} -DOTC_DBG_MEM
diff --git a/scripts/bootstrap b/scripts/bootstrap
new file mode 100755
index 0000000..27c2cf2
--- /dev/null
+++ b/scripts/bootstrap
@@ -0,0 +1,12 @@
+#!/bin/sh -x
+#
+# bootstrap by Miroslav Zagorac <mzagorac@haproxy.com>
+#
+mkdir -p config
+libtoolize
+aclocal -I m4
+autoheader
+automake --add-missing --copy
+autoconf
+
+rm -rf autom4te.cache
diff --git a/scripts/distclean b/scripts/distclean
new file mode 100755
index 0000000..c75fd40
--- /dev/null
+++ b/scripts/distclean
@@ -0,0 +1,9 @@
+#!/bin/sh
+#
+# distclean Miroslav Zagorac <mzagorac@haproxy.com>
+#
+test -f Makefile && make maintainer-clean
+
+rm -rf autom4te.cache config package _*
+rm -f autoscan.log configure.scan aclocal.m4 config.log config.status configure
+rm -f Makefile.in */Makefile.in m4/l* src/.source-md5sums
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..bd72329
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,52 @@
+## Process this file with automake to produce Makefile.in
+##
+##
+AM_CPPFLAGS = @OPENTRACING_C_WRAPPER_CPPFLAGS@
+ AM_CFLAGS = @OPENTRACING_C_WRAPPER_CFLAGS@
+AM_CXXFLAGS = @OPENTRACING_C_WRAPPER_CXXFLAGS@
+ AM_LDFLAGS = @OPENTRACING_C_WRAPPER_LDFLAGS@
+ LIBS = @LIBS@ @OPENTRACING_C_WRAPPER_LIBS@
+
+if WANT_DEBUG
+lib_LTLIBRARIES = libopentracing-c-wrapper_dbg.la
+pkgconfig_DATA = ../opentracing-c-wrapper_dbg.pc
+
+libopentracing_c_wrapper_dbg_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/../include
+libopentracing_c_wrapper_dbg_la_CFLAGS = $(AM_CFLAGS)
+libopentracing_c_wrapper_dbg_la_CXXFLAGS = $(AM_CXXFLAGS)
+libopentracing_c_wrapper_dbg_la_LDFLAGS = $(AM_LDFLAGS) -version-info @LIB_VERSION@ -Wl,--version-script=$(srcdir)/export_dbg.map
+libopentracing_c_wrapper_dbg_la_SOURCES = \
+ dbg_malloc.cpp \
+ span.cpp \
+ tracer.cpp \
+ util.cpp
+
+else
+
+lib_LTLIBRARIES = libopentracing-c-wrapper.la
+pkgconfig_DATA = ../opentracing-c-wrapper.pc
+
+libopentracing_c_wrapper_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/../include
+libopentracing_c_wrapper_la_CFLAGS = $(AM_CFLAGS)
+libopentracing_c_wrapper_la_CXXFLAGS = $(AM_CXXFLAGS)
+libopentracing_c_wrapper_la_LDFLAGS = $(AM_LDFLAGS) -version-info @LIB_VERSION@ -Wl,--version-script=$(srcdir)/export.map
+libopentracing_c_wrapper_la_SOURCES = \
+ span.cpp \
+ tracer.cpp \
+ util.cpp
+endif
+
+pkginclude_HEADERS = \
+ ../include/opentracing-c-wrapper/common.h \
+ ../include/opentracing-c-wrapper/dbg_malloc.h \
+ ../include/opentracing-c-wrapper/define.h \
+ ../include/opentracing-c-wrapper/include.h \
+ ../include/opentracing-c-wrapper/propagation.h \
+ ../include/opentracing-c-wrapper/span.h \
+ ../include/opentracing-c-wrapper/tracer.h \
+ ../include/opentracing-c-wrapper/util.h \
+ ../include/opentracing-c-wrapper/value.h
+
+CLEANFILES = a.out
+##
+## Makefile.am ends here
diff --git a/src/dbg_malloc.cpp b/src/dbg_malloc.cpp
new file mode 100644
index 0000000..18214b1
--- /dev/null
+++ b/src/dbg_malloc.cpp
@@ -0,0 +1,629 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 "include.h"
+
+
+static struct otc_dbg_mem *dbg_mem = nullptr;
+
+
+/***
+ * NAME
+ * otc_dbg_set_metadata -
+ *
+ * ARGUMENTS
+ * ptr - the real address of the allocated data
+ * data -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void otc_dbg_set_metadata(void *ptr, struct otc_dbg_mem_data *data)
+{
+ struct otc_dbg_mem_metadata *metadata;
+
+ if (ptr == nullptr)
+ return;
+
+ metadata = OT_CAST_TYPEOF(metadata, ptr);
+ metadata->data = (data == nullptr) ? OT_CAST_TYPEOF(data, metadata) : data;
+ metadata->magic = DBG_MEM_MAGIC;
+}
+
+
+/***
+ * NAME
+ * otc_dbg_mem_add -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * ptr - the real address of the allocated data
+ * size -
+ * data -
+ * op_idx -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void otc_dbg_mem_add(const char *func, int line, void *ptr, size_t size, struct otc_dbg_mem_data *data, int op_idx)
+{
+ (void)snprintf(data->func, sizeof(data->func), "%s:%d", func, line);
+
+ data->ptr = ptr;
+ data->size = size;
+ data->used = 1;
+
+ dbg_mem->size += size;
+ dbg_mem->op_cnt[op_idx]++;
+
+ otc_dbg_set_metadata(ptr, data);
+}
+
+
+/***
+ * NAME
+ * otc_dbg_mem_alloc -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * old_ptr - the address of the data returned to the program
+ * ptr - the real address of the allocated data
+ * size -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void otc_dbg_mem_alloc(const char *func, int line, void *old_ptr, void *ptr, size_t size)
+{
+ size_t i = 0;
+ int rc;
+
+ if (dbg_mem == nullptr) {
+ return;
+ }
+ else if (ptr == nullptr) {
+ DBG_MEM_ERR("invalid memory address: %p", ptr);
+
+ return;
+ }
+
+ if ((rc = pthread_mutex_lock(&(dbg_mem->mutex))) != 0) {
+ DBG_MEM_ERR("cannot lock mutex: %s", otc_strerror(rc));
+
+ return;
+ }
+
+ if (old_ptr != nullptr) {
+ /* Reallocating memory. */
+ struct otc_dbg_mem_metadata *metadata = OT_CAST_TYPEOF(metadata, ptr);
+
+ if (metadata == nullptr) {
+ DBG_MEM_ERR("no metadata: MEM_REALLOC %s:%d(%p -> %p %zu)", func, line, old_ptr, DBG_MEM_PTR(ptr), size);
+ }
+ else if (metadata->data == nullptr) {
+ DBG_MEM_ERR("invalid metadata: MEM_REALLOC %s:%d(%p -> %p %zu)", func, line, old_ptr, DBG_MEM_PTR(ptr), size);
+ }
+ else if (metadata->data == OT_CAST_TYPEOF(metadata->data, metadata)) {
+ DBG_MEM_ERR("unset metadata: MEM_REALLOC %s:%d(%p -> %p %zu)", func, line, old_ptr, DBG_MEM_PTR(ptr), size);
+ }
+ else if (metadata->magic != DBG_MEM_MAGIC) {
+ DBG_MEM_ERR("invalid magic: MEM_REALLOC %s:%d(%p -> %p %zu) 0x%016" PRIu64, func, line, old_ptr, DBG_MEM_PTR(ptr), size, metadata->magic);
+ }
+ else if (metadata->data->used && (metadata->data->ptr == DBG_MEM_DATA(old_ptr))) {
+ DBG_MEM_INFO(1, "MEM_REALLOC: %s:%d(%p %zu -> %p %zu)", func, line, old_ptr, metadata->data->size, DBG_MEM_PTR(ptr), size);
+
+ dbg_mem->size -= metadata->data->size;
+ otc_dbg_mem_add(func, line, ptr, size, metadata->data, 1);
+ }
+ } else {
+ otc_dbg_set_metadata(ptr, nullptr);
+
+ /*
+ * The first attempt is to find a location that has not been
+ * used at all so far. If such is not found, an attempt is
+ * made to find the first available location.
+ */
+ if (dbg_mem->unused < dbg_mem->count) {
+ i = dbg_mem->unused++;
+ } else {
+ do {
+ if (dbg_mem->reused >= dbg_mem->count)
+ dbg_mem->reused = 0;
+
+ if (!dbg_mem->data[dbg_mem->reused].used) {
+ i = dbg_mem->reused++;
+
+ break;
+ }
+
+ dbg_mem->reused++;
+ } while (++i <= dbg_mem->count);
+ }
+
+ if (i < dbg_mem->count) {
+ DBG_MEM_INFO(1, "MEM_ALLOC: %s:%d(%p %zu %zu)", func, line, DBG_MEM_PTR(ptr), size, i);
+
+ otc_dbg_mem_add(func, line, ptr, size, dbg_mem->data + i, 0);
+ }
+ }
+
+ if ((rc = pthread_mutex_unlock(&(dbg_mem->mutex))) != 0) {
+ DBG_MEM_ERR("cannot unlock mutex: %s", otc_strerror(rc));
+
+ return;
+ }
+
+ if (i >= dbg_mem->count)
+ DBG_MEM_ERR("alloc overflow: %s:%d(%p -> %p %zu)", func, line, old_ptr, DBG_MEM_PTR(ptr), size);
+}
+
+
+/***
+ * NAME
+ * otc_dbg_mem_release -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * ptr - the address of the data returned to the program
+ * op_idx -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void otc_dbg_mem_release(const char *func, int line, void *ptr, int op_idx)
+{
+ struct otc_dbg_mem_metadata *metadata;
+ bool flag_invalid = 0;
+ size_t i;
+ int rc;
+
+ if (dbg_mem == nullptr) {
+ return;
+ }
+ else if (ptr == nullptr) {
+ DBG_MEM_ERR("invalid memory address: %p", ptr);
+
+ return;
+ }
+
+ if ((rc = pthread_mutex_lock(&(dbg_mem->mutex))) != 0) {
+ DBG_MEM_ERR("cannot lock mutex: %s", otc_strerror(rc));
+
+ return;
+ }
+
+ metadata = DBG_MEM_DATA(ptr);
+ if (metadata == nullptr) {
+ DBG_MEM_ERR("no metadata: MEM_%s %s:%d(%p)", (op_idx == 2) ? "FREE" : "RELEASE", func, line, ptr);
+ }
+ else if (metadata->data == nullptr) {
+ DBG_MEM_ERR("invalid metadata: MEM_%s %s:%d(%p)", (op_idx == 2) ? "FREE" : "RELEASE", func, line, ptr);
+ }
+ else if (metadata->data == OT_CAST_TYPEOF(metadata->data, metadata)) {
+ DBG_MEM_ERR("unset metadata: MEM_%s %s:%d(%p)", (op_idx == 2) ? "FREE" : "RELEASE", func, line, ptr);
+ }
+ else if (metadata->magic != DBG_MEM_MAGIC) {
+ DBG_MEM_ERR("invalid magic: MEM_%s %s:%d(%p) 0x%016" PRIu64, (op_idx == 2) ? "FREE" : "RELEASE", func, line, ptr, metadata->magic);
+ }
+ else if (metadata->data->used && (metadata->data->ptr == metadata)) {
+ DBG_MEM_INFO(1, "MEM_%s: %s:%d(%p %zu)", (op_idx == 2) ? "FREE" : "RELEASE", func, line, ptr, metadata->data->size);
+
+ metadata->data->used = 0;
+
+ dbg_mem->size -= metadata->data->size;
+ dbg_mem->op_cnt[op_idx]++;
+ }
+ else {
+ flag_invalid = 1;
+ }
+
+ if ((rc = pthread_mutex_unlock(&(dbg_mem->mutex))) != 0) {
+ DBG_MEM_ERR("cannot unlock mutex: %s", otc_strerror(rc));
+
+ return;
+ }
+
+ if (flag_invalid) {
+ DBG_MEM_ERR("invalid ptr: %s:%d(%p)", func, line, ptr);
+
+ if (metadata != nullptr)
+ for (i = 0; i < dbg_mem->count; i++)
+ if (dbg_mem->data[i].ptr == metadata)
+ DBG_MEM_ERR("possible previous use: %s %hhu", dbg_mem->data[i].func, dbg_mem->data[i].used);
+ }
+}
+
+
+/***
+ * NAME
+ * otc_dbg_malloc -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * size -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+void *otc_dbg_malloc(const char *func, int line, size_t size)
+{
+ void *retptr;
+
+ retptr = malloc(DBG_MEM_SIZE(size));
+
+ otc_dbg_mem_alloc(func, line, nullptr, retptr, size);
+
+ return DBG_MEM_RETURN(retptr);
+}
+
+
+/***
+ * NAME
+ * otc_dbg_calloc -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * nelem -
+ * elsize -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+void *otc_dbg_calloc(const char *func, int line, size_t nelem, size_t elsize)
+{
+ void *retptr;
+
+ retptr = malloc(DBG_MEM_SIZE(nelem * elsize));
+ if (retptr != nullptr)
+ (void)memset(retptr, 0, DBG_MEM_SIZE(nelem * elsize));
+
+ otc_dbg_mem_alloc(func, line, nullptr, retptr, nelem * elsize);
+
+ return DBG_MEM_RETURN(retptr);
+}
+
+
+/***
+ * NAME
+ * otc_dbg_realloc -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * ptr -
+ * size -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+void *otc_dbg_realloc(const char *func, int line, void *ptr, size_t size)
+{
+ void *retptr;
+
+ if (ptr == nullptr) {
+ retptr = malloc(DBG_MEM_SIZE(size));
+
+ otc_dbg_mem_alloc(func, line, nullptr, retptr, size);
+ } else {
+ struct otc_dbg_mem_metadata *metadata = DBG_MEM_DATA(ptr);
+
+ /*
+ * If memory is not allocated via these debug functions, it
+ * must not be reallocated via them either.
+ */
+ if ((metadata == nullptr) || (metadata->data == nullptr) || (metadata->magic != DBG_MEM_MAGIC)) {
+ retptr = realloc(ptr, size);
+
+ return retptr;
+ } else {
+ retptr = realloc(DBG_MEM_DATA(ptr), DBG_MEM_SIZE(size));
+
+ otc_dbg_mem_alloc(func, line, ptr, retptr, size);
+ }
+ }
+
+ return DBG_MEM_RETURN(retptr);
+}
+
+
+/***
+ * NAME
+ * otc_dbg_free -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * ptr -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void otc_dbg_free(const char *func, int line, void *ptr)
+{
+ struct otc_dbg_mem_metadata *metadata;
+
+ otc_dbg_mem_release(func, line, ptr, 2);
+
+ metadata = DBG_MEM_DATA(ptr);
+ if ((metadata == nullptr) || (metadata->data == nullptr) || (metadata->magic != DBG_MEM_MAGIC))
+ free(ptr);
+ else
+ free(DBG_MEM_DATA(ptr));
+}
+
+
+/***
+ * NAME
+ * otc_dbg_strdup -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * s -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+char *otc_dbg_strdup(const char *func, int line, const char *s)
+{
+ size_t len = 0;
+ char *retptr = nullptr;
+
+ if (s != nullptr) {
+ len = strlen(s) + 1;
+ retptr = OT_CAST_TYPEOF(retptr, malloc(DBG_MEM_SIZE(len)));
+ if (retptr != nullptr)
+ (void)memcpy(DBG_MEM_PTR(retptr), s, len);
+ }
+
+ otc_dbg_mem_alloc(func, line, nullptr, retptr, len);
+
+ return OT_CAST_TYPEOF(retptr, DBG_MEM_RETURN(retptr));
+}
+
+
+/***
+ * NAME
+ * otc_dbg_strndup -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * s -
+ * size -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+char *otc_dbg_strndup(const char *func, int line, const char *s, size_t size)
+{
+ size_t len = 0;
+ char *retptr = nullptr;
+
+ if (s != nullptr) {
+ len = strlen(s);
+ len = (len < size) ? len : size;
+ retptr = OT_CAST_TYPEOF(retptr, malloc(DBG_MEM_SIZE(len + 1)));
+ if (retptr != nullptr) {
+ (void)memcpy(DBG_MEM_PTR(retptr), s, len);
+ DBG_MEM_PTR(retptr)[len] = '\0';
+ }
+ }
+
+ otc_dbg_mem_alloc(func, line, nullptr, retptr, len + 1);
+
+ return OT_CAST_TYPEOF(retptr, DBG_MEM_RETURN(retptr));
+}
+
+
+/***
+ * NAME
+ * otc_dbg_mem_init -
+ *
+ * ARGUMENTS
+ * mem -
+ * data -
+ * count -
+ * level -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int otc_dbg_mem_init(struct otc_dbg_mem *mem, struct otc_dbg_mem_data *data, size_t count, uint8_t level)
+{
+ pthread_mutexattr_t attr;
+ int rc, retval = -1;
+
+ if ((mem == nullptr) || (data == nullptr) || (count == 0))
+ return retval;
+
+ (void)memset(mem, 0, sizeof(*mem));
+ (void)memset(data, 0, sizeof(*data) * count);
+
+ dbg_mem = mem;
+ dbg_mem->data = data;
+ dbg_mem->count = count;
+ dbg_mem->level = level;
+
+ if ((rc = pthread_mutexattr_init(&attr)) == 0)
+ if ((rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) == 0)
+ if ((rc = pthread_mutex_init(&(dbg_mem->mutex), &attr)) == 0)
+ retval = 0;
+
+ return retval;
+}
+
+
+/***
+ * NAME
+ * otc_dbg_mem_disable -
+ *
+ * ARGUMENTS
+ * This function takes no arguments.
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void otc_dbg_mem_disable(void)
+{
+ if (dbg_mem == nullptr)
+ return;
+
+ (void)pthread_mutex_destroy(&(dbg_mem->mutex));
+
+ dbg_mem = nullptr;
+}
+
+
+/***
+ * NAME
+ * otc_dbg_mem_info -
+ *
+ * ARGUMENTS
+ * This function takes no arguments.
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void otc_dbg_mem_info(void)
+{
+#ifdef HAVE_MALLINFO
+ struct mallinfo mi;
+#endif
+ size_t i, n = 0;
+ uint64_t size = 0;
+
+ if (dbg_mem == nullptr)
+ return;
+
+ DBG_MEM_INFO(0, "--- Memory info -------------------------------------");
+ DBG_MEM_INFO(0, " alloc/realloc: %" PRIu64 "/%" PRIu64 ", free/release: %" PRIu64 "/%" PRIu64, dbg_mem->op_cnt[0], dbg_mem->op_cnt[1], dbg_mem->op_cnt[2], dbg_mem->op_cnt[3]);
+ DBG_MEM_INFO(0, " unused: %zu, reused: %zu, count: %zu", dbg_mem->unused, dbg_mem->reused, dbg_mem->count);
+ for (i = 0; i < dbg_mem->count; i++)
+ if (dbg_mem->data[i].used) {
+ DBG_MEM_INFO(0, " %zu %s(%p %zu)", n, dbg_mem->data[i].func, dbg_mem->data[i].ptr, dbg_mem->data[i].size);
+
+ size += dbg_mem->data[i].size;
+ n++;
+ }
+
+ if (n > 0)
+ DBG_MEM_INFO(0, " allocated %zu byte(s) in %zu chunk(s)", size, n);
+
+ if (dbg_mem->size != size)
+ DBG_MEM_INFO(0, " size does not match: %zu != %zu", dbg_mem->size, size);
+
+#ifdef HAVE_MALLINFO
+ mi = mallinfo();
+ DBG_MEM_INFO(0, "--- Memory space usage ------------------------------");
+ DBG_MEM_INFO(0, " Total non-mmapped bytes: %" PRI_MI, mi.arena);
+ DBG_MEM_INFO(0, " # of free chunks: %" PRI_MI, mi.ordblks);
+ DBG_MEM_INFO(0, " # of free fastbin blocks: %" PRI_MI, mi.smblks);
+ DBG_MEM_INFO(0, " Bytes in mapped regions: %" PRI_MI, mi.hblkhd);
+ DBG_MEM_INFO(0, " # of mapped regions: %" PRI_MI, mi.hblks);
+ DBG_MEM_INFO(0, " Max. total allocated space: %" PRI_MI, mi.usmblks);
+ DBG_MEM_INFO(0, " Free bytes held in fastbins: %" PRI_MI, mi.fsmblks);
+ DBG_MEM_INFO(0, " Total allocated space: %" PRI_MI, mi.uordblks);
+ DBG_MEM_INFO(0, " Total free space: %" PRI_MI, mi.fordblks);
+ DBG_MEM_INFO(0, " Topmost releasable block: %" PRI_MI, mi.keepcost);
+#endif
+}
+
+
+/***
+ * NAME
+ * otc_dbg_memdup -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * s -
+ * size -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+void *otc_dbg_memdup(const char *func, int line, const void *s, size_t size)
+{
+ void *retptr = nullptr;
+
+ if (s != nullptr) {
+ retptr = malloc(DBG_MEM_SIZE(size + 1));
+ if (retptr != nullptr) {
+ (void)memcpy(DBG_MEM_PTR(retptr), s, size);
+ DBG_MEM_PTR(retptr)[size] = '\0';
+ }
+ }
+
+ otc_dbg_mem_alloc(func, line, nullptr, retptr, size);
+
+ return DBG_MEM_RETURN(retptr);
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/src/export.map b/src/export.map
new file mode 100644
index 0000000..ab7c3a4
--- /dev/null
+++ b/src/export.map
@@ -0,0 +1,18 @@
+{
+global:
+ otc_tracer_init;
+ otc_tracer_load;
+ otc_tracer_start;
+ otc_tracer_global;
+ otc_tracer_init_global;
+ otc_text_map_new;
+ otc_text_map_add;
+ otc_text_map_destroy;
+ otc_binary_data_new;
+ otc_binary_data_destroy;
+ otc_ext_init;
+ otc_file_read;
+ otc_statistics;
+
+local: *;
+};
diff --git a/src/export_dbg.map b/src/export_dbg.map
new file mode 100644
index 0000000..4a99a3f
--- /dev/null
+++ b/src/export_dbg.map
@@ -0,0 +1,29 @@
+{
+global:
+ otc_tracer_init;
+ otc_tracer_load;
+ otc_tracer_start;
+ otc_tracer_global;
+ otc_tracer_init_global;
+ otc_text_map_new;
+ otc_text_map_add;
+ otc_text_map_destroy;
+ otc_binary_data_new;
+ otc_binary_data_destroy;
+ otc_ext_init;
+ otc_file_read;
+ otc_statistics;
+
+ otc_dbg_calloc;
+ otc_dbg_free;
+ otc_dbg_malloc;
+ otc_dbg_mem_disable;
+ otc_dbg_mem_info;
+ otc_dbg_mem_init;
+ otc_dbg_memdup;
+ otc_dbg_realloc;
+ otc_dbg_strdup;
+ otc_dbg_strndup;
+
+local: *;
+};
diff --git a/src/span.cpp b/src/span.cpp
new file mode 100644
index 0000000..3e9323d
--- /dev/null
+++ b/src/span.cpp
@@ -0,0 +1,547 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 "include.h"
+
+
+#ifdef OT_THREADS_NO_LOCKING
+thread_local Handle<opentracing::Span> ot_span_handle;
+thread_local Handle<opentracing::SpanContext> ot_span_context_handle;
+struct HandleData ot_span;
+struct HandleData ot_span_context;
+#else
+struct Handle<opentracing::Span> ot_span;
+struct Handle<opentracing::SpanContext> ot_span_context;
+#endif /* OT_THREADS_NO_LOCKING */
+
+
+/***
+ * NAME
+ * ot_span_finish_with_options -
+ *
+ * ARGUMENTS
+ * span -
+ * options -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_span_finish_with_options(struct otc_span *span, const struct otc_finish_span_options *options)
+{
+ OT_LOCK_GUARD(span);
+
+ if (!OT_SPAN_IS_VALID(span))
+ return;
+
+ if (options == nullptr) {
+ ot_span_handle.at(span->idx)->Finish();
+ } else {
+ struct opentracing::FinishSpanOptions span_options;
+
+ if (options->finish_time.value.tv_sec > 0) {
+ auto dt = timespec_to_duration(&(options->finish_time.value));
+
+ span_options.finish_steady_timestamp = std::chrono::time_point<std::chrono::steady_clock>(dt);
+ }
+
+ if (options->log_records != nullptr) {
+ for (int i = 0; i < options->num_log_records; i++) {
+ struct opentracing::LogRecord record;
+
+ if (options->log_records[i].timestamp.value.tv_sec > 0) {
+#ifdef __clang__
+ auto dt = timespec_to_duration_us(&(options->log_records[i].timestamp.value));
+#else
+ auto dt = timespec_to_duration(&(options->log_records[i].timestamp.value));
+#endif
+
+ record.timestamp = std::chrono::time_point<std::chrono::system_clock>(dt);
+ }
+
+ for (int j = 0; j < options->log_records[i].num_fields; j++)
+ if (options->log_records[i].fields[j].value.type == otc_value_bool) {
+ record.fields.push_back(std::make_pair(options->log_records[i].fields[j].key, options->log_records[i].fields[j].value.value.bool_value));
+ }
+ else if (options->log_records[i].fields[j].value.type == otc_value_double) {
+ record.fields.push_back(std::make_pair(options->log_records[i].fields[j].key, options->log_records[i].fields[j].value.value.double_value));
+ }
+ else if (options->log_records[i].fields[j].value.type == otc_value_int64) {
+ record.fields.push_back(std::make_pair(options->log_records[i].fields[j].key, options->log_records[i].fields[j].value.value.int64_value));
+ }
+ else if (options->log_records[i].fields[j].value.type == otc_value_uint64) {
+ record.fields.push_back(std::make_pair(options->log_records[i].fields[j].key, options->log_records[i].fields[j].value.value.uint64_value));
+ }
+ else if (options->log_records[i].fields[j].value.type == otc_value_string) {
+ std::string str_value = options->log_records[i].fields[j].value.value.string_value;
+
+ record.fields.push_back(std::make_pair(options->log_records[i].fields[j].key, str_value));
+ }
+ else if (options->log_records[i].fields[j].value.type == otc_value_null) {
+ record.fields.push_back(std::make_pair(options->log_records[i].fields[j].key, nullptr));
+ }
+
+ span_options.log_records.push_back(record);
+ }
+ }
+
+ ot_span_handle.at(span->idx)->FinishWithOptions(span_options);
+ }
+
+ ot_nolock_span_destroy(&span);
+}
+
+
+/***
+ * NAME
+ * ot_span_finish -
+ *
+ * ARGUMENTS
+ * span -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_span_finish(struct otc_span *span)
+{
+ ot_span_finish_with_options(span, nullptr);
+}
+
+
+/***
+ * NAME
+ * ot_span_get_context -
+ *
+ * ARGUMENTS
+ * span -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static struct otc_span_context *ot_span_get_context(struct otc_span *span)
+{
+ OT_LOCK(span, span_context);
+
+ if (!OT_SPAN_IS_VALID(span))
+ return nullptr;
+
+ return ot_span_context_new(span);
+}
+
+
+/***
+ * NAME
+ * ot_span_set_operation_name -
+ *
+ * ARGUMENTS
+ * span -
+ * operation_name -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_span_set_operation_name(struct otc_span *span, const char *operation_name)
+{
+ OT_LOCK_GUARD(span);
+
+ if (!OT_SPAN_IS_VALID(span) || (operation_name == nullptr))
+ return;
+
+ ot_span_handle.at(span->idx)->SetOperationName(operation_name);
+}
+
+
+/***
+ * NAME
+ * ot_span_set_tag -
+ *
+ * ARGUMENTS
+ * span -
+ * key -
+ * value -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_span_set_tag(struct otc_span *span, const char *key, const struct otc_value *value)
+{
+ OT_LOCK_GUARD(span);
+
+ if (!OT_SPAN_IS_VALID(span) || (key == nullptr) || (value == nullptr))
+ return;
+
+ if (value->type == otc_value_bool) {
+ ot_span_handle.at(span->idx)->SetTag(key, value->value.bool_value);
+ }
+ else if (value->type == otc_value_double) {
+ ot_span_handle.at(span->idx)->SetTag(key, value->value.double_value);
+ }
+ else if (value->type == otc_value_int64) {
+ ot_span_handle.at(span->idx)->SetTag(key, value->value.int64_value);
+ }
+ else if (value->type == otc_value_uint64) {
+ ot_span_handle.at(span->idx)->SetTag(key, value->value.uint64_value);
+ }
+ else if (value->type == otc_value_string) {
+ std::string str_value = value->value.string_value;
+
+ ot_span_handle.at(span->idx)->SetTag(key, str_value);
+ }
+ else if (value->type == otc_value_null) {
+ ot_span_handle.at(span->idx)->SetTag(key, nullptr);
+ }
+ else {
+ /* Do nothing. */
+ }
+}
+
+
+/***
+ * NAME
+ * ot_span_log_fields -
+ *
+ * ARGUMENTS
+ * span -
+ * fields -
+ * num_fields -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_span_log_fields(struct otc_span *span, const struct otc_log_field *fields, int num_fields)
+{
+ OT_LOCK_GUARD(span);
+ std::string str_value[OTC_MAXLOGFIELDS];
+
+ if (!OT_SPAN_IS_VALID(span) || (fields == nullptr) || !OT_IN_RANGE(num_fields, 1, OTC_MAXLOGFIELDS))
+ return;
+
+ /* XXX The only data type supported in this function is string. */
+ for (int i = 0; (i < num_fields) && (i < OTC_MAXLOGFIELDS); i++) {
+ if (fields[i].value.type != otc_value_string)
+ str_value[i] = "invalid data type";
+ else if (fields[i].value.value.string_value != nullptr)
+ str_value[i] = fields[i].value.value.string_value;
+ else
+ str_value[i] = "";
+ }
+
+ if (num_fields == 1)
+ ot_span_handle.at(span->idx)->Log({ OT_LF(0) });
+ else if (num_fields == 2)
+ ot_span_handle.at(span->idx)->Log({ OT_LF(0), OT_LF(1) });
+ else if (num_fields == 3)
+ ot_span_handle.at(span->idx)->Log({ OT_LF(0), OT_LF(1), OT_LF(2) });
+ else if (num_fields == 4)
+ ot_span_handle.at(span->idx)->Log({ OT_LF(0), OT_LF(1), OT_LF(2), OT_LF(3) });
+ else if (num_fields == 5)
+ ot_span_handle.at(span->idx)->Log({ OT_LF(0), OT_LF(1), OT_LF(2), OT_LF(3), OT_LF(4) });
+ else if (num_fields == 6)
+ ot_span_handle.at(span->idx)->Log({ OT_LF(0), OT_LF(1), OT_LF(2), OT_LF(3), OT_LF(4), OT_LF(5) });
+ else if (num_fields == 7)
+ ot_span_handle.at(span->idx)->Log({ OT_LF(0), OT_LF(1), OT_LF(2), OT_LF(3), OT_LF(4), OT_LF(5), OT_LF(6) });
+ else
+ ot_span_handle.at(span->idx)->Log({ OT_LF(0), OT_LF(1), OT_LF(2), OT_LF(3), OT_LF(4), OT_LF(5), OT_LF(6), OT_LF(7) });
+}
+
+
+/***
+ * NAME
+ * ot_span_set_baggage_item -
+ *
+ * ARGUMENTS
+ * span -
+ * key -
+ * value -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_span_set_baggage_item(struct otc_span *span, const char *key, const char *value)
+{
+ OT_LOCK_GUARD(span);
+
+ if (!OT_SPAN_IS_VALID(span) || (key == nullptr) || (value == nullptr))
+ return;
+
+ ot_span_handle.at(span->idx)->SetBaggageItem(key, value);
+}
+
+
+/***
+ * NAME
+ * ot_span_baggage_item -
+ *
+ * ARGUMENTS
+ * span -
+ * key -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static const char *ot_span_baggage_item(const struct otc_span *span, const char *key)
+{
+ OT_LOCK_GUARD(span);
+ const char *retptr = "";
+
+ if (!OT_SPAN_IS_VALID(span) || (key == nullptr))
+ return retptr;
+
+ auto baggage = ot_span_handle.at(span->idx)->BaggageItem(key);
+ if (!baggage.empty())
+ retptr = OTC_DBG_STRDUP(baggage.c_str());
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * ot_span_tracer -
+ *
+ * ARGUMENTS
+ * span - NOT USED
+ *
+ * DESCRIPTION
+ * - NOT IMPLEMENTED
+ *
+ * RETURN VALUE
+ * -
+ */
+static struct otc_tracer *ot_span_tracer(const struct otc_span *span)
+{
+ struct otc_tracer *retptr = nullptr;
+
+ if (!OT_SPAN_IS_VALID(span))
+ return retptr;
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * ot_nolock_span_destroy -
+ *
+ * ARGUMENTS
+ * span -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void ot_nolock_span_destroy(struct otc_span **span)
+{
+ if ((span == nullptr) || ((*span) == nullptr))
+ return;
+
+ if (OT_SPAN_KEY_IS_VALID(*span)) {
+ ot_span_handle.erase((*span)->idx);
+ ot_span.erase_cnt++;
+ }
+
+ ot_span.destroy_cnt++;
+
+ OT_EXT_FREE_CLEAR(*span);
+}
+
+
+/***
+ * NAME
+ * ot_span_destroy -
+ *
+ * ARGUMENTS
+ * span -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_span_destroy(struct otc_span **span)
+{
+ OT_LOCK_GUARD(span);
+
+ ot_nolock_span_destroy(span);
+}
+
+
+/***
+ * NAME
+ * ot_span_new -
+ *
+ * ARGUMENTS
+ * This function takes no arguments.
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_span *ot_span_new(void)
+{
+ const static struct otc_span span_init = {
+ .idx = 0,
+ .finish = ot_span_finish, /* lock span */
+ .finish_with_options = ot_span_finish_with_options, /* lock span */
+ .span_context = ot_span_get_context, /* lock span and span_context */
+ .set_operation_name = ot_span_set_operation_name, /* lock span */
+ .set_tag = ot_span_set_tag, /* lock span */
+ .log_fields = ot_span_log_fields, /* lock span */
+ .set_baggage_item = ot_span_set_baggage_item, /* lock span */
+ .baggage_item = ot_span_baggage_item, /* lock span */
+ .tracer = ot_span_tracer, /* NOT IMPLEMENTED */
+ .destroy = ot_span_destroy /* lock span */
+ };
+ int64_t idx = ot_span.key++;
+ struct otc_span *retptr;
+
+ if (idx == 0) {
+ ot_span_handle.clear();
+ ot_span_handle.reserve(8192);
+ }
+
+ if ((retptr = OT_CAST_TYPEOF(retptr, OT_EXT_MALLOC(sizeof(*retptr)))) != nullptr) {
+ (void)memcpy(retptr, &span_init, sizeof(*retptr));
+ retptr->idx = idx;
+ } else {
+ ot_span.alloc_fail_cnt++;
+ }
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * ot_nolock_span_context_destroy -
+ *
+ * ARGUMENTS
+ * context -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_nolock_span_context_destroy(struct otc_span_context **context)
+{
+ if ((context == nullptr) || (*context == nullptr))
+ return;
+
+ if (OT_CTX_KEY_IS_VALID(*context)) {
+ ot_span_context_handle.erase((*context)->idx);
+ ot_span_context.erase_cnt++;
+ }
+
+ ot_span_context.destroy_cnt++;
+
+ OT_EXT_FREE_CLEAR(*context);
+}
+
+
+/***
+ * NAME
+ * ot_span_context_destroy -
+ *
+ * ARGUMENTS
+ * context -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_span_context_destroy(struct otc_span_context **context)
+{
+ OT_LOCK_GUARD(span_context);
+
+ ot_nolock_span_context_destroy(context);
+}
+
+
+/***
+ * NAME
+ * ot_span_context_new -
+ *
+ * ARGUMENTS
+ * span -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_span_context *ot_span_context_new(const struct otc_span *span)
+{
+ int64_t idx = ot_span_context.key++;
+ struct otc_span_context *retptr;
+
+ if (idx == 0) {
+ ot_span_context_handle.clear();
+ ot_span_context_handle.reserve(8192);
+ }
+
+ if ((retptr = OT_CAST_TYPEOF(retptr, OT_EXT_MALLOC(sizeof(*retptr)))) == nullptr) {
+ ot_span_context.alloc_fail_cnt++;
+
+ return retptr;
+ }
+
+ retptr->idx = (span == nullptr) ? idx : -1;
+ retptr->span = span;
+ retptr->destroy = ot_span_context_destroy; /* lock span_context */
+
+ return retptr;
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/src/tracer.cpp b/src/tracer.cpp
new file mode 100644
index 0000000..80f56b0
--- /dev/null
+++ b/src/tracer.cpp
@@ -0,0 +1,874 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 "include.h"
+
+
+static std::unique_ptr<const opentracing::DynamicTracingLibraryHandle> ot_dynlib = nullptr;
+static std::shared_ptr<opentracing::Tracer> ot_tracer = nullptr;
+
+
+/***
+ * NAME
+ * ot_tracer_load -
+ *
+ * ARGUMENTS
+ * library -
+ * errbuf -
+ * errbufsiz -
+ * handle -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static int ot_tracer_load(const char *library, char *errbuf, int errbufsiz, opentracing::DynamicTracingLibraryHandle &handle)
+{
+ std::string errmsg;
+
+ /* Load the tracer library. */
+ auto handle_maybe = opentracing::DynamicallyLoadTracingLibrary(library, errmsg);
+ if (!handle_maybe) {
+ (void)snprintf(errbuf, errbufsiz, "Failed to load tracing library: %s", errmsg.empty() ? handle_maybe.error().message().c_str() : errmsg.c_str());
+
+ return -1;
+ }
+
+ handle = std::move(*handle_maybe);
+
+ return 0;
+}
+
+
+/***
+ * NAME
+ * ot_tracer_start -
+ *
+ * ARGUMENTS
+ * config -
+ * errbuf -
+ * errbufsiz -
+ * tracer -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static int ot_tracer_start(const char *config, char *errbuf, int errbufsiz, std::shared_ptr<opentracing::Tracer> &tracer)
+{
+ std::string errmsg;
+
+ auto &tracer_factory = ot_dynlib->tracer_factory();
+
+ /* Create a tracer with the requested configuration. */
+ auto tracer_maybe = tracer_factory.MakeTracer(config, errmsg);
+ if (!tracer_maybe) {
+ (void)snprintf(errbuf, errbufsiz, "Failed to construct tracer: %s", errmsg.empty() ? tracer_maybe.error().message().c_str() : errmsg.c_str());
+
+ return -1;
+ }
+
+ tracer = std::move(*tracer_maybe);
+
+ return 0;
+}
+
+
+/***
+ * NAME
+ * ot_tracer_close -
+ *
+ * ARGUMENTS
+ * tracer -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_tracer_close(struct otc_tracer *tracer)
+{
+ if (tracer == nullptr)
+ return;
+
+ if (ot_dynlib == nullptr)
+ return;
+
+ if (ot_tracer != nullptr)
+ ot_tracer->Close();
+ tracer->destroy(&tracer);
+}
+
+
+/***
+ * NAME
+ * ot_tracer_start_span_with_options -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * operation_name -
+ * options -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static struct otc_span *ot_tracer_start_span_with_options(struct otc_tracer *tracer, const char *operation_name, const struct otc_start_span_options *options)
+{
+ OT_LOCK_GUARD(span);
+ std::unique_ptr<opentracing::Span> span_maybe = nullptr;
+ struct otc_span *retptr = nullptr;
+
+ if (ot_tracer == nullptr)
+ return retptr;
+ else if ((tracer == nullptr) || (operation_name == nullptr))
+ return retptr;
+
+ /* Allocating memory for the span. */
+ if ((retptr = ot_span_new()) == nullptr)
+ return retptr;
+
+ if (options == nullptr) {
+ span_maybe = ot_tracer->StartSpan(operation_name);
+ } else {
+ struct opentracing::StartSpanOptions span_options;
+
+ if (options->start_time_steady.value.tv_sec > 0) {
+ auto dt = timespec_to_duration(&(options->start_time_steady.value));
+
+ span_options.start_steady_timestamp = std::chrono::time_point<std::chrono::steady_clock>(dt);
+ }
+
+ if (options->start_time_system.value.tv_sec > 0) {
+#ifdef __clang__
+ auto dt = timespec_to_duration_us(&(options->start_time_system.value));
+#else
+ auto dt = timespec_to_duration(&(options->start_time_system.value));
+#endif
+
+ span_options.start_system_timestamp = std::chrono::time_point<std::chrono::system_clock>(dt);
+ }
+
+ if (options->references != nullptr) {
+ int lock_cnt = 0;
+
+ for (int i = 0; i < options->num_references; i++) {
+ const opentracing::SpanContext *context = nullptr;
+
+ if (OT_SPAN_IS_VALID(options->references[i].referenced_context->span)) {
+ context = &(ot_span_handle.at(options->references[i].referenced_context->span->idx)->context());
+ }
+ else if (OT_CTX_KEY_IS_VALID(options->references[i].referenced_context)) {
+#ifdef OT_THREADS_NO_LOCKING
+ lock_cnt++;
+#else
+ if (lock_cnt++ == 0)
+ ot_span_context.mutex.lock();
+#endif
+
+ context = ot_span_context_handle.at(options->references[i].referenced_context->idx).get();
+ }
+
+ if (options->references[i].type == otc_span_reference_child_of)
+ span_options.references.push_back(std::make_pair(opentracing::SpanReferenceType::ChildOfRef, context));
+ else if (options->references[i].type == otc_span_reference_follows_from)
+ span_options.references.push_back(std::make_pair(opentracing::SpanReferenceType::FollowsFromRef, context));
+ }
+
+#ifndef OT_THREADS_NO_LOCKING
+ if (lock_cnt > 0)
+ ot_span_context.mutex.unlock();
+#endif
+ }
+
+ if (options->tags != nullptr) {
+ for (int i = 0; i < options->num_tags; i++)
+ if (options->tags[i].value.type == otc_value_bool) {
+ span_options.tags.push_back(std::make_pair(options->tags[i].key, options->tags[i].value.value.bool_value));
+ }
+ else if (options->tags[i].value.type == otc_value_double) {
+ span_options.tags.push_back(std::make_pair(options->tags[i].key, options->tags[i].value.value.double_value));
+ }
+ else if (options->tags[i].value.type == otc_value_int64) {
+ span_options.tags.push_back(std::make_pair(options->tags[i].key, options->tags[i].value.value.int64_value));
+ }
+ else if (options->tags[i].value.type == otc_value_uint64) {
+ span_options.tags.push_back(std::make_pair(options->tags[i].key, options->tags[i].value.value.uint64_value));
+ }
+ else if (options->tags[i].value.type == otc_value_string) {
+ std::string str_value = options->tags[i].value.value.string_value;
+
+ span_options.tags.push_back(std::make_pair(options->tags[i].key, str_value));
+ }
+ else if (options->tags[i].value.type == otc_value_null) {
+ span_options.tags.push_back(std::make_pair(options->tags[i].key, nullptr));
+ }
+ }
+
+ span_maybe = ot_tracer->StartSpanWithOptions(operation_name, span_options);
+ }
+
+ if (span_maybe != nullptr)
+ ot_span_handle.emplace(retptr->idx, std::move(span_maybe));
+ else
+ ot_nolock_span_destroy(&retptr);
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * ot_tracer_start_span -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * operation_name -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static struct otc_span *ot_tracer_start_span(struct otc_tracer *tracer, const char *operation_name)
+{
+ return ot_tracer_start_span_with_options(tracer, operation_name, nullptr);
+}
+
+
+/***
+ * NAME
+ * ot_tracer_inject_text_map -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * carrier -
+ * span_context -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_tracer_inject_text_map(struct otc_tracer *tracer, struct otc_text_map_writer *carrier, const struct otc_span_context *span_context)
+{
+ TextMap text_map;
+ TextMapCarrier text_map_carrier(text_map);
+ opentracing::expected<void> rc;
+
+ if (ot_tracer == nullptr)
+ return otc_propagation_error_code_invalid_tracer;
+ else if ((tracer == nullptr) || (carrier == nullptr))
+ return otc_propagation_error_code_invalid_carrier;
+ else if (!OT_CTX_IS_VALID(span_context))
+ return otc_propagation_error_code_span_context_corrupted;
+
+ if (OT_SPAN_IS_VALID(span_context->span)) {
+ OT_LOCK_GUARD(span);
+
+ rc = ot_tracer->Inject(ot_span_handle.at(span_context->span->idx)->context(), text_map_carrier);
+ }
+ else if (OT_CTX_KEY_IS_VALID(span_context)) {
+ OT_LOCK_GUARD(span_context);
+
+ rc = ot_tracer->Inject(*(ot_span_context_handle.at(span_context->idx)), text_map_carrier);
+ }
+
+ if (!rc)
+ return otc_propagation_error_code_unknown;
+ else if (text_map.empty())
+ return otc_propagation_error_code_unknown;
+ else if (otc_text_map_new(&(carrier->text_map), text_map.size()) == nullptr)
+ return otc_propagation_error_code_unknown;
+
+ for (auto const &it : text_map)
+ if (carrier->set != nullptr) {
+ otc_propagation_error_code_t retval = carrier->set(carrier, it.first.c_str(), it.second.c_str());
+ if (retval != otc_propagation_error_code_success)
+ return retval;
+ }
+ else if (otc_text_map_add(&(carrier->text_map), it.first.c_str(), 0, it.second.c_str(), 0, OT_CAST_STAT(otc_text_map_flags_t, OTC_TEXT_MAP_DUP_KEY | OTC_TEXT_MAP_DUP_VALUE)) == -1)
+ return otc_propagation_error_code_unknown;
+
+ return otc_propagation_error_code_success;
+}
+
+
+/***
+ * NAME
+ * ot_tracer_inject_http_headers -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * carrier -
+ * span_context -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_tracer_inject_http_headers(struct otc_tracer *tracer, struct otc_http_headers_writer *carrier, const struct otc_span_context *span_context)
+{
+ TextMap text_map;
+ HTTPHeadersCarrier http_headers_carrier(text_map);
+ opentracing::expected<void> rc;
+
+ if (ot_tracer == nullptr)
+ return otc_propagation_error_code_invalid_tracer;
+ else if ((tracer == nullptr) || (carrier == nullptr))
+ return otc_propagation_error_code_invalid_carrier;
+ else if (!OT_CTX_IS_VALID(span_context))
+ return otc_propagation_error_code_span_context_corrupted;
+
+ if (OT_SPAN_IS_VALID(span_context->span)) {
+ OT_LOCK_GUARD(span);
+
+ rc = ot_tracer->Inject(ot_span_handle.at(span_context->span->idx)->context(), http_headers_carrier);
+ }
+ else if (OT_CTX_KEY_IS_VALID(span_context)) {
+ OT_LOCK_GUARD(span_context);
+
+ rc = ot_tracer->Inject(*(ot_span_context_handle.at(span_context->idx)), http_headers_carrier);
+ }
+
+ if (!rc)
+ return otc_propagation_error_code_unknown;
+ else if (text_map.empty())
+ return otc_propagation_error_code_unknown;
+ else if (otc_text_map_new(&(carrier->text_map), text_map.size()) == nullptr)
+ return otc_propagation_error_code_unknown;
+
+ for (auto const &it : text_map)
+ if (carrier->set != nullptr) {
+ otc_propagation_error_code_t retval = carrier->set(carrier, it.first.c_str(), it.second.c_str());
+ if (retval != otc_propagation_error_code_success)
+ return retval;
+ }
+ else if (otc_text_map_add(&(carrier->text_map), it.first.c_str(), 0, it.second.c_str(), 0, OT_CAST_STAT(otc_text_map_flags_t, OTC_TEXT_MAP_DUP_KEY | OTC_TEXT_MAP_DUP_VALUE)) == -1)
+ return otc_propagation_error_code_unknown;
+
+ return otc_propagation_error_code_success;
+}
+
+
+/***
+ * NAME
+ * ot_tracer_inject_binary -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * carrier -
+ * span_context -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_tracer_inject_binary(struct otc_tracer *tracer, struct otc_custom_carrier_writer *carrier, const struct otc_span_context *span_context)
+{
+ std::ostringstream oss(std::ios::binary);
+ opentracing::expected<void> rc;
+
+ if (ot_tracer == nullptr)
+ return otc_propagation_error_code_invalid_tracer;
+ else if ((tracer == nullptr) || (carrier == nullptr))
+ return otc_propagation_error_code_invalid_carrier;
+ else if (!OT_CTX_IS_VALID(span_context))
+ return otc_propagation_error_code_span_context_corrupted;
+
+ if (OT_SPAN_IS_VALID(span_context->span)) {
+ OT_LOCK_GUARD(span);
+
+ rc = ot_tracer->Inject(ot_span_handle.at(span_context->span->idx)->context(), oss);
+ }
+ else if (OT_CTX_KEY_IS_VALID(span_context)) {
+ OT_LOCK_GUARD(span_context);
+
+ rc = ot_tracer->Inject(*(ot_span_context_handle.at(span_context->idx)), oss);
+ }
+
+ if (rc)
+ if (otc_binary_data_new(&(carrier->binary_data), oss.str().c_str(), oss.str().size()) != nullptr)
+ return otc_propagation_error_code_success;
+
+ return otc_propagation_error_code_unknown;
+}
+
+
+/***
+ * NAME
+ * ot_tracer_inject_custom -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * carrier - NOT USED
+ * span_context - NOT USED
+ *
+ * DESCRIPTION
+ * - NOT IMPLEMENTED
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_tracer_inject_custom(struct otc_tracer *tracer, struct otc_custom_carrier_writer *carrier, const struct otc_span_context *span_context)
+{
+ if ((tracer == nullptr) || (carrier == nullptr))
+ return otc_propagation_error_code_invalid_carrier;
+ else if (!OT_CTX_IS_VALID(span_context))
+ return otc_propagation_error_code_span_context_corrupted;
+
+ return otc_propagation_error_code_success;
+}
+
+
+/***
+ * NAME
+ * ot_span_context_add -
+ *
+ * ARGUMENTS
+ * span_context -
+ * span_context_maybe -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_span_context_add(struct otc_span_context **span_context, std::unique_ptr<opentracing::SpanContext> &span_context_maybe)
+{
+ OT_LOCK_GUARD(span_context);
+
+ if ((*span_context = ot_span_context_new(nullptr)) == nullptr) {
+ span_context_maybe.reset(nullptr);
+
+ return otc_propagation_error_code_unknown;
+ }
+
+ ot_span_context_handle.emplace((*span_context)->idx, std::move(span_context_maybe));
+
+ return otc_propagation_error_code_success;
+}
+
+
+/***
+ * NAME
+ * ot_tracer_text_map_add -
+ *
+ * ARGUMENTS
+ * arg -
+ * key -
+ * value -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_tracer_text_map_add(void *arg, const char *key, const char *value)
+{
+ TextMap *text_map = OT_CAST_REINTERPRET(TextMap *, arg);
+
+ if ((arg == nullptr) || (key == nullptr) || (value == nullptr))
+ return otc_propagation_error_code_unknown;
+
+ text_map->emplace(key, value);
+
+ return otc_propagation_error_code_success;
+}
+
+
+/***
+ * NAME
+ * ot_tracer_extract_text_map -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * carrier -
+ * span_context -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_tracer_extract_text_map(struct otc_tracer *tracer, const struct otc_text_map_reader *carrier, struct otc_span_context **span_context)
+{
+ TextMap text_map;
+ TextMapCarrier text_map_carrier(text_map);
+
+ if (ot_tracer == nullptr)
+ return otc_propagation_error_code_invalid_tracer;
+ else if ((tracer == nullptr) || (carrier == nullptr))
+ return otc_propagation_error_code_invalid_carrier;
+ else if (span_context == nullptr)
+ return otc_propagation_error_code_invalid_span_context;
+
+ if (carrier->foreach_key != nullptr) {
+ otc_propagation_error_code_t rc = carrier->foreach_key(OT_CAST_CONST(struct otc_text_map_reader *, carrier), ot_tracer_text_map_add, &text_map);
+ if (rc != otc_propagation_error_code_success)
+ return rc;
+ } else {
+ for (size_t i = 0; i < carrier->text_map.count; i++)
+ text_map[carrier->text_map.key[i]] = carrier->text_map.value[i];
+ }
+
+ auto span_context_maybe = ot_tracer->Extract(text_map_carrier);
+ if (!span_context_maybe)
+ return otc_propagation_error_code_span_context_not_found;
+
+ return ot_span_context_add(span_context, *span_context_maybe);
+}
+
+
+/***
+ * NAME
+ * ot_tracer_extract_http_headers -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * carrier -
+ * span_context -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_tracer_extract_http_headers(struct otc_tracer *tracer, const struct otc_http_headers_reader *carrier, struct otc_span_context **span_context)
+{
+ TextMap text_map;
+ HTTPHeadersCarrier http_headers_carrier(text_map);
+
+ if (ot_tracer == nullptr)
+ return otc_propagation_error_code_invalid_tracer;
+ else if ((tracer == nullptr) || (carrier == nullptr))
+ return otc_propagation_error_code_invalid_carrier;
+ else if (span_context == nullptr)
+ return otc_propagation_error_code_invalid_span_context;
+
+ if (carrier->foreach_key != nullptr) {
+ otc_propagation_error_code_t rc = carrier->foreach_key(OT_CAST_CONST(struct otc_http_headers_reader *, carrier), ot_tracer_text_map_add, &text_map);
+ if (rc != otc_propagation_error_code_success)
+ return rc;
+ } else {
+ for (size_t i = 0; i < carrier->text_map.count; i++)
+ text_map[carrier->text_map.key[i]] = carrier->text_map.value[i];
+ }
+
+ auto span_context_maybe = ot_tracer->Extract(http_headers_carrier);
+ if (!span_context_maybe)
+ return otc_propagation_error_code_span_context_not_found;
+
+ return ot_span_context_add(span_context, *span_context_maybe);
+}
+
+
+/***
+ * NAME
+ * ot_tracer_extract_binary -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * carrier -
+ * span_context -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_tracer_extract_binary(struct otc_tracer *tracer, const struct otc_custom_carrier_reader *carrier, struct otc_span_context **span_context)
+{
+ if (ot_tracer == nullptr)
+ return otc_propagation_error_code_invalid_tracer;
+ else if ((tracer == nullptr) || (carrier == nullptr))
+ return otc_propagation_error_code_invalid_carrier;
+ else if (span_context == nullptr)
+ return otc_propagation_error_code_invalid_span_context;
+
+ if ((carrier->binary_data.data == nullptr) || (carrier->binary_data.size == 0))
+ return otc_propagation_error_code_invalid_carrier;
+
+ std::string iss_data(OT_CAST_REINTERPRET(const char *, carrier->binary_data.data), carrier->binary_data.size);
+ std::istringstream iss(iss_data, std::ios::binary);
+
+ auto span_context_maybe = ot_tracer->Extract(iss);
+ if (!span_context_maybe)
+ return otc_propagation_error_code_span_context_not_found;
+
+ return ot_span_context_add(span_context, *span_context_maybe);
+}
+
+
+/***
+ * NAME
+ * ot_tracer_extract_custom -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ * carrier - NOT USED
+ * span_context - NOT USED
+ *
+ * DESCRIPTION
+ * - NOT IMPLEMENTED
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_tracer_extract_custom(struct otc_tracer *tracer, const struct otc_custom_carrier_reader *carrier, struct otc_span_context **span_context)
+{
+ if ((tracer == nullptr) || (carrier == nullptr) || (span_context == nullptr))
+ return otc_propagation_error_code_unknown;
+
+ return otc_propagation_error_code_success;
+}
+
+
+/***
+ * NAME
+ * ot_tracer_destroy -
+ *
+ * ARGUMENTS
+ * tracer -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_tracer_destroy(struct otc_tracer **tracer)
+{
+ if ((tracer == nullptr) || (*tracer == nullptr))
+ return;
+
+ OT_FREE_CLEAR(*tracer);
+}
+
+
+/***
+ * NAME
+ * ot_tracer_new -
+ *
+ * ARGUMENTS
+ * This function takes no arguments.
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_tracer *ot_tracer_new(void)
+{
+ const static struct otc_tracer tracer_init = {
+ .close = ot_tracer_close, /* lock not required */
+ .start_span = ot_tracer_start_span, /* lock span */
+ .start_span_with_options = ot_tracer_start_span_with_options, /* lock span */
+ .inject_text_map = ot_tracer_inject_text_map, /* lock span and/or span_context */
+ .inject_http_headers = ot_tracer_inject_http_headers, /* lock span and/or span_context */
+ .inject_binary = ot_tracer_inject_binary, /* lock span and/or span_context */
+ .inject_custom = ot_tracer_inject_custom, /* NOT IMPLEMENTED */
+ .extract_text_map = ot_tracer_extract_text_map, /* lock span_context */
+ .extract_http_headers = ot_tracer_extract_http_headers, /* lock span_context */
+ .extract_binary = ot_tracer_extract_binary, /* lock span_context */
+ .extract_custom = ot_tracer_extract_custom, /* NOT IMPLEMENTED */
+ .destroy = ot_tracer_destroy /* lock not required */
+ };
+ struct otc_tracer *retptr;
+
+ if ((retptr = OT_CAST_TYPEOF(retptr, OTC_DBG_CALLOC(1, sizeof(*retptr)))) != nullptr)
+ (void)memcpy(retptr, &tracer_init, sizeof(*retptr));
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * otc_tracer_load -
+ *
+ * ARGUMENTS
+ * library -
+ * errbuf -
+ * errbufsiz -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_tracer *otc_tracer_load(const char *library, char *errbuf, int errbufsiz)
+{
+ std::unique_ptr<opentracing::DynamicTracingLibraryHandle> handle {
+ new opentracing::DynamicTracingLibraryHandle {}
+ };
+ std::shared_ptr<opentracing::Tracer> tracer;
+ struct otc_tracer *retptr = nullptr;
+
+ if ((retptr = ot_tracer_new()) == nullptr) {
+ /* Do nothing. */;
+ }
+ else if (ot_tracer_load(library, errbuf, errbufsiz, *handle) == -1) {
+ retptr->destroy(&retptr);
+ }
+ else {
+ ot_dynlib = std::move(handle);
+ }
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * otc_tracer_start -
+ *
+ * ARGUMENTS
+ * cfgfile -
+ * cfgbuf -
+ * errbuf -
+ * errbufsiz -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int otc_tracer_start(const char *cfgfile, const char *cfgbuf, char *errbuf, int errbufsiz)
+{
+ std::shared_ptr<opentracing::Tracer> tracer;
+ char *config = OT_CAST_CONST(char *, cfgbuf);
+ int retval = -1;
+
+ if (cfgfile != nullptr) {
+ config = otc_file_read(cfgfile, "#", errbuf, errbufsiz);
+ if (config == nullptr)
+ return retval;
+ }
+
+ if (ot_tracer_start(config, errbuf, errbufsiz, tracer) == -1) {
+ /* Do nothing. */;
+ } else {
+ ot_tracer = std::move(tracer);
+
+ (void)opentracing::Tracer::InitGlobal(ot_tracer);
+
+ retval = 0;
+ }
+
+ if (config != cfgbuf)
+ OT_FREE(config);
+
+ return retval;
+}
+
+
+/***
+ * NAME
+ * otc_tracer_init -
+ *
+ * ARGUMENTS
+ * library -
+ * cfgfile -
+ * cfgbuf -
+ * errbuf -
+ * errbufsiz -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_tracer *otc_tracer_init(const char *library, const char *cfgfile, const char *cfgbuf, char *errbuf, int errbufsiz)
+{
+ struct otc_tracer *retptr = nullptr;
+
+ if ((retptr = otc_tracer_load(library, errbuf, errbufsiz)) != nullptr)
+ if (otc_tracer_start(cfgfile, cfgbuf, errbuf, errbufsiz) == -1)
+ retptr->destroy(&retptr);
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * otc_tracer_global -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ *
+ * DESCRIPTION
+ * - NOT IMPLEMENTED
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void otc_tracer_global(struct otc_tracer *tracer)
+{
+ if (tracer == nullptr)
+ return;
+}
+
+
+/***
+ * NAME
+ * otc_tracer_init_global -
+ *
+ * ARGUMENTS
+ * tracer - NOT USED
+ *
+ * DESCRIPTION
+ * - NOT IMPLEMENTED
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void otc_tracer_init_global(struct otc_tracer *tracer)
+{
+ if (tracer == nullptr)
+ return;
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/src/util.cpp b/src/util.cpp
new file mode 100644
index 0000000..3236e9d
--- /dev/null
+++ b/src/util.cpp
@@ -0,0 +1,451 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 "include.h"
+
+
+otc_ext_malloc_t otc_ext_malloc = OT_IFDEF_DBG(otc_dbg_malloc, malloc);
+otc_ext_free_t otc_ext_free = OT_IFDEF_DBG(otc_dbg_free, free);
+
+
+/***
+ * NAME
+ * timespec_to_duration_us -
+ *
+ * ARGUMENTS
+ * ts -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+std::chrono::microseconds timespec_to_duration_us(const struct timespec *ts)
+{
+ auto duration = std::chrono::seconds{ts->tv_sec} + std::chrono::microseconds{ts->tv_nsec / 1000};
+
+ return std::chrono::duration_cast<std::chrono::microseconds>(duration);
+}
+
+
+/***
+ * NAME
+ * timespec_to_duration -
+ *
+ * ARGUMENTS
+ * ts -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+std::chrono::nanoseconds timespec_to_duration(const struct timespec *ts)
+{
+ auto duration = std::chrono::seconds{ts->tv_sec} + std::chrono::nanoseconds{ts->tv_nsec};
+
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(duration);
+}
+
+
+/***
+ * NAME
+ * otc_ext_init -
+ *
+ * ARGUMENTS
+ * func_malloc -
+ * func_free -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void otc_ext_init(otc_ext_malloc_t func_malloc, otc_ext_free_t func_free)
+{
+ otc_ext_malloc = (func_malloc != nullptr) ? func_malloc : OT_IFDEF_DBG(otc_dbg_malloc, malloc);
+ otc_ext_free = (func_free != nullptr) ? func_free : OT_IFDEF_DBG(otc_dbg_free, free);
+}
+
+
+/***
+ * NAME
+ * otc_text_map_new -
+ *
+ * ARGUMENTS
+ * text_map -
+ * size -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_text_map *otc_text_map_new(struct otc_text_map *text_map, size_t size)
+{
+ struct otc_text_map *retptr = text_map;
+
+ if (retptr == nullptr)
+ retptr = OT_CAST_TYPEOF(retptr, OTC_DBG_CALLOC(1, sizeof(*retptr)));
+
+ if (retptr != nullptr) {
+ retptr->count = 0;
+ retptr->size = size;
+ retptr->is_dynamic = text_map == nullptr;
+
+ if (size == 0)
+ /* Do nothing. */;
+ else if ((retptr->key = OT_CAST_TYPEOF(retptr->key, OTC_DBG_CALLOC(size, sizeof(*(retptr->key))))) == nullptr)
+ otc_text_map_destroy(&retptr, OT_CAST_STAT(otc_text_map_flags_t, 0));
+ else if ((retptr->value = OT_CAST_TYPEOF(retptr->value, OTC_DBG_CALLOC(size, sizeof(*(retptr->value))))) == nullptr)
+ otc_text_map_destroy(&retptr, OT_CAST_STAT(otc_text_map_flags_t, 0));
+ }
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * otc_text_map_add -
+ *
+ * ARGUMENTS
+ * text_map -
+ * key -
+ * key_len -
+ * value -
+ * value_len -
+ * flags -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int otc_text_map_add(struct otc_text_map *text_map, const char *key, size_t key_len, const char *value, size_t value_len, otc_text_map_flags_t flags)
+{
+ int retval = -1;
+
+ if ((text_map == nullptr) || (key == nullptr) || (value == nullptr))
+ return retval;
+
+ /*
+ * Check if it is necessary to increase the number of key/value pairs.
+ * The number of pairs is increased by half the current number of pairs
+ * (for example: 8 -> 12 -> 18 -> 27 -> 40 -> 60 ...).
+ */
+ if (text_map->count >= text_map->size) {
+ typeof(text_map->key) ptr_key;
+ typeof(text_map->value) ptr_value;
+ size_t size_add = (text_map->size > 1) ? (text_map->size / 2) : 1;
+
+ if ((ptr_key = OT_CAST_TYPEOF(ptr_key, OTC_DBG_REALLOC(text_map->key, OT_TEXT_MAP_SIZE(key, size_add)))) == nullptr)
+ return retval;
+
+ text_map->key = ptr_key;
+ (void)memset(text_map->key + OT_TEXT_MAP_SIZE(key, 0), 0, sizeof(*(text_map->key)) * size_add);
+
+ if ((ptr_value = OT_CAST_TYPEOF(ptr_value, OTC_DBG_REALLOC(text_map->value, OT_TEXT_MAP_SIZE(value, size_add)))) == nullptr)
+ return retval;
+
+ text_map->value = ptr_value;
+ (void)memset(text_map->value + OT_TEXT_MAP_SIZE(value, 0), 0, sizeof(*(text_map->value)) * size_add);
+
+ text_map->size += size_add;
+ }
+
+ text_map->key[text_map->count] = (flags & OTC_TEXT_MAP_DUP_KEY) ? ((key_len > 0) ? OTC_DBG_STRNDUP(key, key_len) : OTC_DBG_STRDUP(key)) : OT_CAST_CONST(char *, key);
+ text_map->value[text_map->count] = (flags & OTC_TEXT_MAP_DUP_VALUE) ? ((value_len > 0) ? OTC_DBG_STRNDUP(value, value_len) : OTC_DBG_STRDUP(value)) : OT_CAST_CONST(char *, value);
+
+ if ((text_map->key[text_map->count] != nullptr) && (text_map->value[text_map->count] != nullptr))
+ retval = text_map->count;
+
+ text_map->count++;
+
+ return retval;
+}
+
+
+/***
+ * NAME
+ * otc_text_map_destroy -
+ *
+ * ARGUMENTS
+ * text_map -
+ * flags -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void otc_text_map_destroy(struct otc_text_map **text_map, otc_text_map_flags_t flags)
+{
+ if ((text_map == nullptr) || (*text_map == nullptr))
+ return;
+
+ if ((*text_map)->key != nullptr) {
+ if (flags & OTC_TEXT_MAP_FREE_KEY)
+ for (size_t i = 0; i < (*text_map)->count; i++)
+ OT_FREE((*text_map)->key[i]);
+
+ OT_FREE_CLEAR((*text_map)->key);
+ }
+
+ if ((*text_map)->value != nullptr) {
+ if (flags & OTC_TEXT_MAP_FREE_VALUE)
+ for (size_t i = 0; i < (*text_map)->count; i++)
+ OT_FREE((*text_map)->value[i]);
+
+ OT_FREE_CLEAR((*text_map)->value);
+ }
+
+ if ((*text_map)->is_dynamic) {
+ OT_FREE_CLEAR(*text_map);
+ } else {
+ (*text_map)->count = 0;
+ (*text_map)->size = 0;
+ }
+}
+
+
+/***
+ * NAME
+ * otc_binary_data_new -
+ *
+ * ARGUMENTS
+ * binary_data -
+ * data -
+ * size -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_binary_data *otc_binary_data_new(struct otc_binary_data *binary_data, const void *data, size_t size)
+{
+ struct otc_binary_data *retptr = binary_data;
+
+ if (retptr == nullptr)
+ retptr = OT_CAST_TYPEOF(retptr, OTC_DBG_CALLOC(1, sizeof(*retptr)));
+
+ if (retptr != nullptr) {
+ retptr->size = size;
+ retptr->is_dynamic = binary_data == nullptr;
+
+ if ((data == nullptr) || (size == 0))
+ /* Do nothing. */;
+ else if ((retptr->data = OTC_DBG_MALLOC(size)) != nullptr)
+ (void)memcpy(retptr->data, data, size);
+ else
+ otc_binary_data_destroy(&retptr);
+ }
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * otc_binary_data_destroy -
+ *
+ * ARGUMENTS
+ * binary_data -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void otc_binary_data_destroy(struct otc_binary_data **binary_data)
+{
+ if ((binary_data == nullptr) || (*binary_data == nullptr))
+ return;
+
+ OT_FREE_CLEAR((*binary_data)->data);
+
+ if ((*binary_data)->is_dynamic)
+ OT_FREE_CLEAR(*binary_data);
+ else
+ (*binary_data)->size = 0;
+}
+
+
+/***
+ * NAME
+ * otc_strerror -
+ *
+ * ARGUMENTS
+ * errnum -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+const char *otc_strerror(int errnum)
+{
+ static __THR char retbuf[1024];
+ const char *retptr = retbuf;
+
+ errno = 0;
+ (void)strerror_r(errnum, retbuf, sizeof(retbuf));
+ if (errno != 0)
+ retptr = "Unknown error";
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * otc_file_read -
+ *
+ * ARGUMENTS
+ * filename -
+ * comment -
+ * errbuf -
+ * errbufsiz -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+char *otc_file_read(const char *filename, const char *comment, char *errbuf, int errbufsiz)
+{
+ struct stat statbuf;
+ char *retptr = nullptr;
+ int fd, rc;
+
+ if (filename == nullptr)
+ return retptr;
+
+ if ((fd = open(filename, O_RDONLY)) == -1) {
+ (void)snprintf(errbuf, errbufsiz, "'%s': %s", filename, otc_strerror(errno));
+ }
+ else if ((rc = fstat(fd, &statbuf)) == -1) {
+ (void)snprintf(errbuf, errbufsiz, "'%s': %s", filename, otc_strerror(errno));
+ }
+ else if ((retptr = OT_CAST_TYPEOF(retptr, OTC_DBG_MALLOC(statbuf.st_size + 1))) == nullptr) {
+ (void)snprintf(errbuf, errbufsiz, "cannot allocate memory: %s", otc_strerror(errno));
+ }
+ else {
+ char *buf = retptr;
+ off_t size = statbuf.st_size;
+
+ while (size > 0) {
+ ssize_t n;
+
+ if ((n = read(fd, buf, size)) > 0) {
+ size -= n;
+ buf += n;
+ }
+ else if (n == -1) {
+ if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
+ break;
+ }
+ else if (errno != EINTR)
+ {
+ (void)snprintf(errbuf, errbufsiz, "'%s': %s", filename, otc_strerror(errno));
+ OT_FREE_CLEAR(retptr);
+
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ }
+
+ if (comment != nullptr) {
+ off_t i = 0, c = -1, n = statbuf.st_size;
+
+ for (i = 0; i < n; i++)
+ if (c < 0) {
+ /* Remember the starting position of the comment line. */
+ if ((strchr(comment, retptr[i]) != nullptr) && ((i == 0) || (retptr[i - 1] == '\n')))
+ c = i;
+ }
+ else if ((retptr[i] == '\n') && ((i + 1) < n)) {
+ /* Delete the entire comment line. */
+ (void)memmove(retptr + c, retptr + i + 1, n - i - 1);
+
+ n -= i + 1 - c;
+ i = c - 1;
+ c = -1;
+ }
+
+ /* If a comment remains in the last line, delete it. */
+ if (c >= 0) {
+ n -= i - c;
+ i = c;
+ }
+
+ retptr[i] = '\0';
+ }
+ else if (size != 0)
+ OT_FREE_CLEAR(retptr);
+ }
+
+ (void)close(fd);
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * otc_statistics -
+ *
+ * ARGUMENTS
+ * buffer -
+ * bufsiz -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void otc_statistics(char *buffer, size_t bufsiz)
+{
+ if ((buffer == nullptr) || (bufsiz < 24))
+ return;
+
+ (void)snprintf(buffer, bufsiz, "span: %" PRId64 "/%" PRId64 "+%" PRId64 "(%" PRId64 ")/%" PRId64 ", context: %" PRId64 "/%" PRId64 "+%" PRId64 "(%" PRId64 ")/%" PRId64,
+ ot_span.key, ot_span_handle.size(), ot_span.erase_cnt, ot_span.destroy_cnt, ot_span.alloc_fail_cnt,
+ ot_span_context.key, ot_span_context_handle.size(), ot_span_context.erase_cnt, ot_span_context.destroy_cnt, ot_span_context.alloc_fail_cnt);
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..72b61e7
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,23 @@
+## Process this file with automake to produce Makefile.in
+##
+ AM_CPPFLAGS = -I\$(top_builddir)/include -I$(srcdir)/../include @OPENTRACING_C_WRAPPER_CPPFLAGS@
+ AM_CFLAGS = @OPENTRACING_C_WRAPPER_CFLAGS@
+ AM_LDFLAGS = @OPENTRACING_C_WRAPPER_LDFLAGS@
+
+if WANT_DEBUG
+ bin_PROGRAMS = ot-c-wrapper-test_dbg
+ot_c_wrapper_test_dbg_SOURCES = opentracing.c test.c util.c
+ ot_c_wrapper_test_dbg_LDADD = -lstdc++ -lm @OPENTRACING_C_WRAPPER_LIBS@ $(top_builddir)/src/libopentracing-c-wrapper_dbg.la
+ot_c_wrapper_test_dbg_LDFLAGS = @OPENTRACING_C_WRAPPER_LDFLAGS@
+
+else
+
+ bin_PROGRAMS = ot-c-wrapper-test
+ot_c_wrapper_test_SOURCES = opentracing.c test.c util.c
+ ot_c_wrapper_test_LDADD = -lstdc++ -lm @OPENTRACING_C_WRAPPER_LIBS@ $(top_builddir)/src/libopentracing-c-wrapper.la
+ot_c_wrapper_test_LDFLAGS = @OPENTRACING_C_WRAPPER_LDFLAGS@
+endif
+
+CLEANFILES = a.out
+##
+## Makefile.am ends here
diff --git a/test/cfg-dd.json b/test/cfg-dd.json
new file mode 100644
index 0000000..5763d06
--- /dev/null
+++ b/test/cfg-dd.json
@@ -0,0 +1,5 @@
+{
+ "service": "opentracing-c-wrapper-test",
+ "agent_host": "localhost",
+ "agent_port": 8126
+}
diff --git a/test/cfg-jaeger.yml b/test/cfg-jaeger.yml
new file mode 100644
index 0000000..ca3904f
--- /dev/null
+++ b/test/cfg-jaeger.yml
@@ -0,0 +1,34 @@
+service_name:
+ opentracing-c-wrapper-test
+
+###
+# When using configuration object to instantiate the tracer, the type of
+# sampling can be selected via sampler.type and sampler.param properties.
+# Jaeger libraries support the following samplers:
+#
+# - Constant (sampler.type=const) sampler always makes the same decision for
+# all traces. It either samples all traces (sampler.param=1) or none of
+# them (sampler.param=0).
+#
+# - Probabilistic (sampler.type=probabilistic) sampler makes a random sampling
+# decision with the probability of sampling equal to the value of
+# sampler.param property. For example, with sampler.param=0.1 approximately
+# 1 in 10 traces will be sampled.
+#
+# - Rate Limiting (sampler.type=ratelimiting) sampler uses a leaky bucket rate
+# limiter to ensure that traces are sampled with a certain constant rate.
+# For example, when sampler.param=2.0 it will sample requests with the rate
+# of 2 traces per second.
+#
+# - Remote (sampler.type=remote, which is also the default) sampler consults
+# Jaeger agent for the appropriate sampling strategy to use in the current
+# service. This allows controlling the sampling strategies in the services
+# from a central configuration in Jaeger backend, or even dynamically.
+#
+sampler:
+ type: ratelimiting
+ param: 10.0
+
+reporter:
+ logSpans: true
+ localAgentHostPort: localhost:6831
diff --git a/test/cfg-zipkin.json b/test/cfg-zipkin.json
new file mode 100644
index 0000000..e25634f
--- /dev/null
+++ b/test/cfg-zipkin.json
@@ -0,0 +1,4 @@
+{
+ "service_name": "opentracing-c-wrapper-test",
+ "collector_host": "localhost"
+}
diff --git a/test/debug.h b/test/debug.h
new file mode 100644
index 0000000..c8d22b8
--- /dev/null
+++ b/test/debug.h
@@ -0,0 +1,58 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 TEST_DEBUG_H
+#define TEST_DEBUG_H
+
+#define OT_LOG(f,...) (void)printf("[%4d] " f "\n", thread_id(), ##__VA_ARGS__)
+
+#ifdef DEBUG
+enum DBG_LEVEL_enum {
+ DBG_LEVEL_FUNC = 0, /* Function debug level. */
+ DBG_LEVEL_INFO, /* Generic info level. */
+ DBG_LEVEL_DEBUG, /* Generic debug level. */
+ DBG_LEVEL_OT, /* OpenTracing debug level. */
+ DBG_LEVEL_WORKER, /* Worker debug level. */
+ DBG_LEVEL_ENABLED, /* This have to be the last entry. */
+};
+
+# define OT_FUNC(f,...) \
+ do { \
+ if (_nNULL(cfg_debug_level) && (*cfg_debug_level > 0)) \
+ OT_LOG("%s(" f ")", __func__, ##__VA_ARGS__); \
+ } while (0)
+# define OT_DBG(l,f,...) \
+ do { \
+ if (_nNULL(cfg_debug_level) && (*cfg_debug_level & (1 << DBG_LEVEL_##l))) \
+ OT_LOG(" " f, ##__VA_ARGS__); \
+ } while (0)
+
+
+extern uint8_t *cfg_debug_level;
+#else
+# define OT_FUNC(...) do { } while (0)
+# define OT_DBG(...) do { } while (0)
+#endif /* DEBUG */
+
+#endif /* TEST_DEBUG_H */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/test/define.h b/test/define.h
new file mode 100644
index 0000000..68dcf60
--- /dev/null
+++ b/test/define.h
@@ -0,0 +1,61 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 TEST_DEFINE_H
+#define TEST_DEFINE_H
+
+#ifdef DEBUG
+# define OTC_DBG_MEM
+#endif
+
+#ifndef PACKAGE_BUILD
+# define PACKAGE_BUILD 0
+#endif
+
+#define OT_USE_INJECT_CB
+#define OT_USE_EXTRACT_CB
+
+#ifdef __linux__
+# define PRI_PIDT "d"
+# define PRI_PTHREADT "lu"
+#else
+# define PRI_PIDT "ld"
+# define PRI_PTHREADT "u"
+#endif
+
+#ifndef MIN
+# define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#define _NULL(a) ((a) == NULL)
+#define _nNULL(a) ((a) != NULL)
+#define TABLESIZE(a) ((int)(sizeof(a) / sizeof((a)[0])))
+#define IN_RANGE(v,a,b) (((v) >= (a)) && ((v) <= (b)))
+#define TIMEVAL_DIFF_MS(a,b) (((a)->tv_sec - (b)->tv_sec) * 1000ULL + ((a)->tv_usec - (b)->tv_usec + 500) / 1000)
+#define TIMEVAL_DIFF_US(a,b) (((a)->tv_sec - (b)->tv_sec) * 1000000ULL + (a)->tv_usec - (b)->tv_usec)
+#define NIBBLE_TO_HEX(a) ((a) + (((a) < 10) ? '0' : ('a' - 10)))
+#define SWAP(a,b) do { typeof(a) _a = (a); (a) = (b); (b) = _a; } while (0)
+#define OT_VARGS(t,v) otc_value_##t, (v)
+
+#endif /* TEST_DEFINE_H */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/test/get-opentracing-plugins.sh b/test/get-opentracing-plugins.sh
new file mode 100755
index 0000000..f2fe2d6
--- /dev/null
+++ b/test/get-opentracing-plugins.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+#
+_ARG_DIR="${1:-.}"
+
+
+get ()
+{
+ local _arg_tracer="${1}"
+ local _arg_version="${2}"
+ local _arg_url="${3}"
+ local _arg_file="${4}"
+ local _var_tmpfile="_tmpfile_"
+ local _var_plugin="lib${_arg_tracer}_opentracing_plugin-${_arg_version}.so"
+
+ test -e "${_var_plugin}" && return 0
+
+ wget "https://github.com/${_arg_url}/releases/download/v${_arg_version}/${_arg_file}" -O "${_var_tmpfile}" || {
+ rm "${_var_tmpfile}"
+ return 1
+ }
+
+ case "$(file ${_var_tmpfile})" in
+ *shared\ object*)
+ mv "${_var_tmpfile}" "${_var_plugin}" ;;
+
+ *gzip\ compressed\ data*)
+ gzip -cd "${_var_tmpfile}" > "${_var_plugin}"
+ rm "${_var_tmpfile}" ;;
+ esac
+}
+
+
+mkdir -p "${_ARG_DIR}" && cd "${_ARG_DIR}" || exit 1
+
+get dd 1.1.2 DataDog/dd-opentracing-cpp linux-amd64-libdd_opentracing_plugin.so.gz
+get dd 1.2.0 DataDog/dd-opentracing-cpp linux-amd64-libdd_opentracing_plugin.so.gz
+
+get jaeger 0.4.2 jaegertracing/jaeger-client-cpp libjaegertracing_plugin.linux_amd64.so
+#et jaeger 0.5.0 jaegertracing/jaeger-client-cpp libjaegertracing_plugin.linux_amd64.so
+#et jaeger 0.6.0 jaegertracing/jaeger-client-cpp libjaegertracing_plugin.linux_amd64.so
+
+get lightstep 0.12.0 lightstep/lightstep-tracer-cpp linux-amd64-liblightstep_tracer_plugin.so.gz
+get lightstep 0.13.0 lightstep/lightstep-tracer-cpp linux-amd64-liblightstep_tracer_plugin.so.gz
+
+get zipkin 0.5.2 rnburn/zipkin-cpp-opentracing linux-amd64-libzipkin_opentracing_plugin.so.gz
diff --git a/test/include.h b/test/include.h
new file mode 100644
index 0000000..328ba72
--- /dev/null
+++ b/test/include.h
@@ -0,0 +1,67 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 TEST_INCLUDE_H
+#define TEST_INCLUDE_H
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <pthread.h>
+#include <sysexits.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef __linux__
+# include <sys/syscall.h>
+#endif
+
+#include "config.h"
+#include "define.h"
+
+#include "opentracing-c-wrapper/define.h"
+#include "opentracing-c-wrapper/dbg_malloc.h"
+#include "opentracing-c-wrapper/common.h"
+#include "opentracing-c-wrapper/util.h"
+#include "opentracing-c-wrapper/value.h"
+#include "opentracing-c-wrapper/span.h"
+#include "opentracing-c-wrapper/propagation.h"
+#include "opentracing-c-wrapper/tracer.h"
+
+#include "version.h"
+#include "debug.h"
+#include "opentracing.h"
+#include "util.h"
+
+#endif /* TEST_INCLUDE_H */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/test/opentracing.c b/test/opentracing.c
new file mode 100644
index 0000000..2e30fe5
--- /dev/null
+++ b/test/opentracing.c
@@ -0,0 +1,771 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 "include.h"
+
+
+static void ot_text_map_show(const struct otc_text_map *text_map)
+{
+ OT_FUNC("%p", text_map);
+
+ if (_NULL(text_map))
+ return;
+
+ OT_DBG(OT, "%p:{ %p %p %zu/%zu %hhu }", text_map, text_map->key, text_map->value, text_map->count, text_map->size, text_map->is_dynamic);
+
+ if (_nNULL(text_map->key) && _nNULL(text_map->value) && (text_map->count > 0)) {
+ size_t i;
+
+ for (i = 0; i < text_map->count; i++)
+ OT_DBG(OT, " \"%s\" -> \"%s\"", text_map->key[i], text_map->value[i]);
+ }
+}
+
+
+/***
+ * NAME
+ * ot_span_init -
+ *
+ * ARGUMENTS
+ * operation_name -
+ * ref_type -
+ * ref_ctx_idx -
+ * ref_span -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_span *ot_span_init(struct otc_tracer *tracer, const char *operation_name, int ref_type, int ref_ctx_idx, const struct otc_span *ref_span)
+{
+ struct otc_start_span_options options;
+ struct otc_span_context context = { .idx = ref_ctx_idx, .span = ref_span };
+ struct otc_span_reference references = { ref_type, &context };
+ struct otc_span *retptr = NULL;
+
+ OT_FUNC("%p, \"%s\", %d, %d, %p", tracer, operation_name, ref_type, ref_ctx_idx, ref_span);
+
+ (void)memset(&options, 0, sizeof(options));
+
+ if (IN_RANGE(ref_type, otc_span_reference_child_of, otc_span_reference_follows_from)) {
+ options.references = &references;
+ options.num_references = 1;
+ }
+
+ retptr = tracer->start_span_with_options(tracer, operation_name, &options);
+ if (_NULL(retptr))
+ OT_DBG(OT, "cannot init new span");
+ else
+ OT_DBG(OT, "span %p:%zu initialized", retptr, retptr->idx);
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * ot_span_tag -
+ *
+ * ARGUMENTS
+ * span -
+ * key -
+ * type -
+ * value -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int ot_span_tag(struct otc_span *span, const char *key, int type, ...)
+{
+ va_list ap;
+ struct otc_value ot_value;
+ int retval = -1;
+
+ OT_FUNC("%p, \"%s\", %d, ...", span, key, type);
+
+ if (_NULL(span))
+ return retval;
+
+ va_start(ap, type);
+ for (retval = 0; _nNULL(key) && IN_RANGE(type, otc_value_bool, otc_value_null); retval++) {
+ ot_value.type = type;
+ if (type == otc_value_bool)
+ ot_value.value.bool_value = va_arg(ap, typeof(ot_value.value.bool_value));
+ else if (type == otc_value_double)
+ ot_value.value.double_value = va_arg(ap, typeof(ot_value.value.double_value));
+ else if (type == otc_value_int64)
+ ot_value.value.int64_value = va_arg(ap, typeof(ot_value.value.int64_value));
+ else if (type == otc_value_uint64)
+ ot_value.value.uint64_value = va_arg(ap, typeof(ot_value.value.uint64_value));
+ else if (type == otc_value_string)
+ ot_value.value.string_value = va_arg(ap, typeof(ot_value.value.string_value));
+ else if (type == otc_value_null)
+ ot_value.value.string_value = va_arg(ap, typeof(ot_value.value.string_value));
+ span->set_tag(span, key, &ot_value);
+
+ if (_nNULL(key = va_arg(ap, typeof(key))))
+ type = va_arg(ap, typeof(type));
+ }
+ va_end(ap);
+
+ return retval;
+}
+
+
+/***
+ * NAME
+ * ot_span_set_baggage -
+ *
+ * ARGUMENTS
+ * span -
+ * key -
+ * value -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int ot_span_set_baggage(struct otc_span *span, const char *key, const char *value, ...)
+{
+ va_list ap;
+ int retval = -1;
+
+ OT_FUNC("%p, \"%s\", \"%s\", ...", span, key, value);
+
+ if (_NULL(span))
+ return retval;
+
+ va_start(ap, value);
+ for (retval = 0; _nNULL(key); retval++) {
+ OT_DBG(OT, "set baggage: \"%s\" \"%s\"", key, value);
+
+ span->set_baggage_item(span, key, value);
+
+ if (_nNULL(key = va_arg(ap, typeof(key))))
+ value = va_arg(ap, typeof(value));
+ }
+ va_end(ap);
+
+ return retval;
+}
+
+
+/***
+ * NAME
+ * ot_span_baggage -
+ *
+ * ARGUMENTS
+ * span -
+ * key -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_text_map *ot_span_baggage(const struct otc_span *span, const char *key, ...)
+{
+ va_list ap;
+ struct otc_text_map *retptr = NULL;
+ int i, n;
+
+ OT_FUNC("%p, \"%s\", ...", span, key);
+
+ if (_NULL(span) || _NULL(key))
+ return retptr;
+
+ va_start(ap, key);
+ for (n = 1; _nNULL(va_arg(ap, typeof(key))); n++);
+ va_end(ap);
+
+ if (_NULL(retptr = otc_text_map_new(NULL, n)))
+ return retptr;
+
+ va_start(ap, key);
+ for (i = 0; (i < n) && _nNULL(key); i++) {
+ char *value;
+
+ if (_nNULL(value = (char *)span->baggage_item(span, key))) {
+ (void)otc_text_map_add(retptr, key, 0, value, 0, OTC_TEXT_MAP_DUP_KEY);
+
+ OT_DBG(OT, "get baggage[%d]: \"%s\" -> \"%s\"", i, retptr->key[i], retptr->value[i]);
+ } else {
+ OT_DBG(OT, "get baggage[%d]: \"%s\" -> invalid key", i, key);
+ }
+
+ key = va_arg(ap, typeof(key));
+ }
+ va_end(ap);
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * ot_span_log_kv -
+ *
+ * ARGUMENTS
+ * span -
+ * key -
+ * value -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int ot_span_log_kv(struct otc_span *span, const char *key, const char *value, ...)
+{
+ va_list ap;
+ struct otc_log_field log_data[OTC_MAXLOGFIELDS];
+ int retval = -1;
+
+ OT_FUNC("%p, \"%s\", \"%s\", ...", span, key, value);
+
+ if (_NULL(span) || _NULL(key) || _NULL(value))
+ return retval;
+
+ va_start(ap, value);
+ for (retval = 0; (retval < TABLESIZE(log_data)) && _nNULL(key); retval++) {
+ log_data[retval].key = key;
+ log_data[retval].value.type = otc_value_string;
+ log_data[retval].value.value.string_value = value;
+
+ if (_nNULL(key = va_arg(ap, typeof(key))))
+ value = va_arg(ap, typeof(value));
+ }
+ va_end(ap);
+
+ span->log_fields(span, log_data, retval);
+
+ return retval;
+}
+
+
+/***
+ * NAME
+ * ot_span_log -
+ *
+ * ARGUMENTS
+ * span -
+ * key -
+ * format -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int ot_span_log(struct otc_span *span, const char *key, const char *format, ...)
+{
+ va_list ap;
+ char value[BUFSIZ];
+
+ OT_FUNC("%p, \"%s\", \"%s\", ...", span, key, format);
+
+ if (_NULL(span) || _NULL(key) || _NULL(format))
+ return -1;
+
+ va_start(ap, format);
+ (void)vsnprintf(value, sizeof(value), format, ap);
+ va_end(ap);
+
+ return ot_span_log_kv(span, key, value, NULL);
+}
+
+
+#ifdef OT_USE_INJECT_CB
+
+/***
+ * NAME
+ * ot_text_map_writer_set_cb -
+ *
+ * ARGUMENTS
+ * writer -
+ * key -
+ * value -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_text_map_writer_set_cb(struct otc_text_map_writer *writer, const char *key, const char *value)
+{
+ otc_propagation_error_code_t retval = otc_propagation_error_code_success;
+
+ OT_FUNC("%p, \"%s\", \"%s\"", writer, key, value);
+
+ if (otc_text_map_add(&(writer->text_map), key, 0, value, 0, OTC_TEXT_MAP_DUP_KEY | OTC_TEXT_MAP_DUP_VALUE) == -1)
+ retval = otc_propagation_error_code_unknown;
+
+ return retval;
+}
+
+#endif /* OT_USE_INJECT_CB */
+
+
+#ifdef OT_USE_EXTRACT_CB
+
+/***
+ * NAME
+ * ot_text_map_reader_foreach_key_cb -
+ *
+ * ARGUMENTS
+ * reader -
+ * handler -
+ * arg -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_text_map_reader_foreach_key_cb(struct otc_text_map_reader *reader, otc_propagation_error_code_t (*handler)(void *arg, const char *key, const char *value), void *arg)
+{
+ size_t i;
+ otc_propagation_error_code_t retval = otc_propagation_error_code_success;
+
+ OT_FUNC("%p, %p, %p", reader, handler, arg);
+
+ for (i = 0; (retval == otc_propagation_error_code_success) && (i < reader->text_map.count); i++) {
+ OT_DBG(OT, "\"%s\" -> \"%s\"", reader->text_map.key[i], reader->text_map.value[i]);
+
+ retval = handler(arg, reader->text_map.key[i], reader->text_map.value[i]);
+ }
+
+ return retval;
+}
+
+#endif /* OT_USE_EXTRACT_CB */
+
+
+/***
+ * NAME
+ * ot_inject_text_map -
+ *
+ * ARGUMENTS
+ * tracer -
+ * span -
+ * carrier -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_span_context *ot_inject_text_map(struct otc_tracer *tracer, const struct otc_span *span, struct otc_text_map_writer *carrier)
+{
+ struct otc_span_context *retptr = NULL;
+ int rc;
+
+ OT_FUNC("%p, %p, %p", tracer, span, carrier);
+
+ if (_NULL(span))
+ return retptr;
+
+ if (_NULL(retptr = span->span_context((struct otc_span *)span)))
+ return retptr;
+
+ (void)memset(carrier, 0, sizeof(*carrier));
+#ifdef OT_USE_INJECT_CB
+ carrier->set = ot_text_map_writer_set_cb;
+#endif
+
+ rc = tracer->inject_text_map(tracer, carrier, retptr);
+ if (rc != otc_propagation_error_code_success) {
+ OT_LOG(" ERROR: inject_text_map() failed: %d", rc);
+
+ OTC_DBG_FREE(retptr);
+ } else {
+ OT_DBG(OT, "context %p: { %" PRId64 " %p %p }", retptr, retptr->idx, retptr->span, retptr->destroy);
+ }
+
+ OT_DBG(OT, "carrier %p: { { %p %p %zu/%zu %hhu } %p }", carrier, carrier->text_map.key, carrier->text_map.value, carrier->text_map.count, carrier->text_map.size, carrier->text_map.is_dynamic, carrier->set);
+ ot_text_map_show(&(carrier->text_map));
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * ot_extract_text_map -
+ *
+ * ARGUMENTS
+ * tracer -
+ * carrier -
+ * text_map -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_span_context *ot_extract_text_map(struct otc_tracer *tracer, struct otc_text_map_reader *carrier, const struct otc_text_map *text_map)
+{
+ struct otc_span_context *retptr = NULL;
+ int rc;
+
+ OT_FUNC("%p, %p, %p", tracer, carrier, text_map);
+
+ (void)memset(carrier, 0, sizeof(*carrier));
+#ifdef OT_USE_EXTRACT_CB
+ carrier->foreach_key = ot_text_map_reader_foreach_key_cb;
+#endif
+
+ if (_nNULL(text_map))
+ (void)memcpy(&(carrier->text_map), text_map, sizeof(carrier->text_map));
+
+ OT_DBG(OT, "carrier %p: { { %p %p %zu/%zu %hhu } }", carrier, carrier->text_map.key, carrier->text_map.value, carrier->text_map.count, carrier->text_map.size, carrier->text_map.is_dynamic);
+
+ rc = tracer->extract_text_map(tracer, carrier, &retptr);
+ if (rc != otc_propagation_error_code_success) {
+ OT_LOG(" ERROR: extract_text_map() failed: %d", rc);
+
+ OTC_DBG_FREE(retptr);
+ }
+ else if (_nNULL(retptr)) {
+ OT_DBG(OT, "context %p: { %" PRId64 " %p %p }", retptr, retptr->idx, retptr->span, retptr->destroy);
+ }
+
+ return retptr;
+}
+
+
+#ifdef OT_USE_INJECT_CB
+
+/***
+ * NAME
+ * ot_http_headers_writer_set_cb -
+ *
+ * ARGUMENTS
+ * writer -
+ * key -
+ * value -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_http_headers_writer_set_cb(struct otc_http_headers_writer *writer, const char *key, const char *value)
+{
+ otc_propagation_error_code_t retval = otc_propagation_error_code_success;
+
+ OT_FUNC("%p, \"%s\", \"%s\"", writer, key, value);
+
+ if (otc_text_map_add(&(writer->text_map), key, 0, value, 0, OTC_TEXT_MAP_DUP_KEY | OTC_TEXT_MAP_DUP_VALUE) == -1)
+ retval = otc_propagation_error_code_unknown;
+
+ return retval;
+}
+
+#endif /* OT_USE_INJECT_CB */
+
+
+#ifdef OT_USE_EXTRACT_CB
+
+/***
+ * NAME
+ * ot_http_headers_reader_foreach_key_cb -
+ *
+ * ARGUMENTS
+ * reader -
+ * handler -
+ * arg -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static otc_propagation_error_code_t ot_http_headers_reader_foreach_key_cb(struct otc_http_headers_reader *reader, otc_propagation_error_code_t (*handler)(void *arg, const char *key, const char *value), void *arg)
+{
+ size_t i;
+ otc_propagation_error_code_t retval = otc_propagation_error_code_success;
+
+ OT_FUNC("%p, %p, %p", reader, handler, arg);
+
+ for (i = 0; (retval == otc_propagation_error_code_success) && (i < reader->text_map.count); i++) {
+ OT_DBG(OT, "\"%s\" -> \"%s\"", reader->text_map.key[i], reader->text_map.value[i]);
+
+ retval = handler(arg, reader->text_map.key[i], reader->text_map.value[i]);
+ }
+
+ return retval;
+}
+
+#endif /* OT_USE_EXTRACT_CB */
+
+
+/***
+ * NAME
+ * ot_inject_http_headers -
+ *
+ * ARGUMENTS
+ * tracer -
+ * span -
+ * carrier -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_span_context *ot_inject_http_headers(struct otc_tracer *tracer, const struct otc_span *span, struct otc_http_headers_writer *carrier)
+{
+ struct otc_span_context *retptr = NULL;
+ int rc;
+
+ OT_FUNC("%p, %p, %p", tracer, span, carrier);
+
+ if (_NULL(span))
+ return retptr;
+
+ if (_NULL(retptr = span->span_context((struct otc_span *)span)))
+ return retptr;
+
+ (void)memset(carrier, 0, sizeof(*carrier));
+#ifdef OT_USE_INJECT_CB
+ carrier->set = ot_http_headers_writer_set_cb;
+#endif
+
+ rc = tracer->inject_http_headers(tracer, carrier, retptr);
+ if (rc != otc_propagation_error_code_success) {
+ OT_LOG(" ERROR: inject_http_headers() failed: %d", rc);
+
+ OTC_DBG_FREE(retptr);
+ } else {
+ OT_DBG(OT, "context %p: { %" PRId64 " %p %p }", retptr, retptr->idx, retptr->span, retptr->destroy);
+ }
+
+ OT_DBG(OT, "carrier %p: { { %p %p %zu/%zu %hhu } %p }", carrier, carrier->text_map.key, carrier->text_map.value, carrier->text_map.count, carrier->text_map.size, carrier->text_map.is_dynamic, carrier->set);
+ ot_text_map_show(&(carrier->text_map));
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * ot_extract_http_headers -
+ *
+ * ARGUMENTS
+ * tracer -
+ * carrier -
+ * text_map -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_span_context *ot_extract_http_headers(struct otc_tracer *tracer, struct otc_http_headers_reader *carrier, const struct otc_text_map *text_map)
+{
+ struct otc_span_context *retptr = NULL;
+ int rc;
+
+ OT_FUNC("%p, %p, %p", tracer, carrier, text_map);
+
+ (void)memset(carrier, 0, sizeof(*carrier));
+#ifdef OT_USE_EXTRACT_CB
+ carrier->foreach_key = ot_http_headers_reader_foreach_key_cb;
+#endif
+
+ if (_nNULL(text_map))
+ (void)memcpy(&(carrier->text_map), text_map, sizeof(carrier->text_map));
+
+ OT_DBG(OT, "carrier %p: { { %p %p %zu/%zu %hhu } }", carrier, carrier->text_map.key, carrier->text_map.value, carrier->text_map.count, carrier->text_map.size, carrier->text_map.is_dynamic);
+
+ rc = tracer->extract_http_headers(tracer, carrier, &retptr);
+ if (rc != otc_propagation_error_code_success) {
+ OT_LOG(" ERROR: extract_http_headers() failed: %d", rc);
+
+ OTC_DBG_FREE(retptr);
+ }
+ else if (_nNULL(retptr)) {
+ OT_DBG(OT, "context %p: { %" PRId64 " %p %p }", retptr, retptr->idx, retptr->span, retptr->destroy);
+ }
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * ot_inject_binary -
+ *
+ * ARGUMENTS
+ * tracer -
+ * span -
+ * carrier -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_span_context *ot_inject_binary(struct otc_tracer *tracer, const struct otc_span *span, struct otc_custom_carrier_writer *carrier)
+{
+ struct otc_span_context *retptr = NULL;
+ int rc;
+
+ OT_FUNC("%p, %p, %p", tracer, span, carrier);
+
+ if (_NULL(span))
+ return retptr;
+
+ if (_NULL(retptr = span->span_context((struct otc_span *)span)))
+ return retptr;
+
+ (void)memset(carrier, 0, sizeof(*carrier));
+
+ rc = tracer->inject_binary(tracer, carrier, retptr);
+ if (rc != otc_propagation_error_code_success) {
+ OT_LOG(" ERROR: inject_binary() failed: %d", rc);
+
+ OTC_DBG_FREE(retptr);
+ } else {
+ OT_DBG(OT, "context %p: { %" PRId64 " %p %p }", retptr, retptr->idx, retptr->span, retptr->destroy);
+ }
+
+ OT_DBG(OT, "carrier %p: { { %p %zu %hhu } %p }", carrier, carrier->binary_data.data, carrier->binary_data.size, carrier->binary_data.is_dynamic, carrier->inject);
+
+#ifdef DEBUG
+ if (carrier->binary_data.data != NULL) {
+ struct otc_jaeger_trace_context *ctx_jaeger = carrier->binary_data.data;
+ struct otc_dd_trace_context *ctx_dd = carrier->binary_data.data;
+
+ OT_DBG(OT, "Jaeger trace context: %016" PRIx64 "%016" PRIx64 ":%016" PRIx64 ":%016" PRIx64 ":%02hhx <%s> <%s>",
+ ctx_jaeger->trace_id[0], ctx_jaeger->trace_id[1], ctx_jaeger->span_id, ctx_jaeger->parent_span_id, ctx_jaeger->flags,
+ str_hex(ctx_jaeger->baggage, carrier->binary_data.size - sizeof(*ctx_jaeger)),
+ str_ctrl(ctx_jaeger->baggage, carrier->binary_data.size - sizeof(*ctx_jaeger)));
+ OT_DBG(OT, "DataDog trace context: <%s> <%s>",
+ str_hex(ctx_dd->data, carrier->binary_data.size),
+ str_ctrl(ctx_dd->data, carrier->binary_data.size));
+ }
+#endif /* DEBUG */
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * ot_extract_binary -
+ *
+ * ARGUMENTS
+ * tracer -
+ * carrier -
+ * binary_data -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_span_context *ot_extract_binary(struct otc_tracer *tracer, struct otc_custom_carrier_reader *carrier, const struct otc_binary_data *binary_data)
+{
+ struct otc_span_context *retptr = NULL;
+ int rc;
+
+ OT_FUNC("%p, %p, %p", tracer, carrier, binary_data);
+
+ (void)memset(carrier, 0, sizeof(*carrier));
+
+ if (_nNULL(binary_data) && _nNULL(binary_data->data) && (binary_data->size > 0))
+ (void)memcpy(&(carrier->binary_data), binary_data, sizeof(carrier->binary_data));
+
+ OT_DBG(OT, "carrier %p: { { %p %zu %hhu } %p }", carrier, carrier->binary_data.data, carrier->binary_data.size, carrier->binary_data.is_dynamic, carrier->extract);
+
+ rc = tracer->extract_binary(tracer, carrier, &retptr);
+ if (rc != otc_propagation_error_code_success) {
+ OT_LOG(" ERROR: extract_binary() failed: %d", rc);
+
+ OTC_DBG_FREE(retptr);
+ }
+ else if (_nNULL(retptr)) {
+ OT_DBG(OT, "context %p: { %" PRId64 " %p %p }", retptr, retptr->idx, retptr->span, retptr->destroy);
+ }
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * ot_span_finish -
+ *
+ * ARGUMENTS
+ * span -
+ * ts_finish -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void ot_span_finish(struct otc_span **span, const struct timespec *ts_finish)
+{
+ struct otc_finish_span_options options;
+
+ OT_FUNC("%p, %p", span, ts_finish);
+
+ if (_NULL(span) || _NULL(*span))
+ return;
+
+ (void)memset(&options, 0, sizeof(options));
+
+ if (_nNULL(ts_finish))
+ (void)memcpy(&(options.finish_time.value), ts_finish, sizeof(options.finish_time.value));
+
+ OT_DBG(OT, "span %p:%zu finished", *span, (*span)->idx);
+
+ (*span)->finish_with_options(*span, &options);
+
+ *span = NULL;
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/test/opentracing.h b/test/opentracing.h
new file mode 100644
index 0000000..7cb4b99
--- /dev/null
+++ b/test/opentracing.h
@@ -0,0 +1,42 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 TEST_OPENTRACING_H
+#define TEST_OPENTRACING_H
+
+struct otc_span *ot_span_init(struct otc_tracer *tracer, const char *operation_name, int ref_type, int ref_ctx_idx, const struct otc_span *ref_span);
+int ot_span_tag(struct otc_span *span, const char *key, int type, ...);
+int ot_span_set_baggage(struct otc_span *span, const char *key, const char *value, ...);
+struct otc_text_map *ot_span_baggage(const struct otc_span *span, const char *key, ...);
+int ot_span_log_kv(struct otc_span *span, const char *key, const char *value, ...);
+int ot_span_log(struct otc_span *span, const char *key, const char *format, ...);
+struct otc_span_context *ot_inject_text_map(struct otc_tracer *tracer, const struct otc_span *span, struct otc_text_map_writer *carrier);
+struct otc_span_context *ot_extract_text_map(struct otc_tracer *tracer, struct otc_text_map_reader *carrier, const struct otc_text_map *text_map);
+struct otc_span_context *ot_inject_http_headers(struct otc_tracer *tracer, const struct otc_span *span, struct otc_http_headers_writer *carrier);
+struct otc_span_context *ot_extract_http_headers(struct otc_tracer *tracer, struct otc_http_headers_reader *carrier, const struct otc_text_map *text_map);
+struct otc_span_context *ot_inject_binary(struct otc_tracer *tracer, const struct otc_span *span, struct otc_custom_carrier_writer *carrier);
+struct otc_span_context *ot_extract_binary(struct otc_tracer *tracer, struct otc_custom_carrier_reader *carrier, const struct otc_binary_data *binary_data);
+void ot_span_finish(struct otc_span **span, const struct timespec *ts_finish);
+
+#endif /* TEST_OPENTRACING_H */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/test/test.c b/test/test.c
new file mode 100644
index 0000000..287e4e2
--- /dev/null
+++ b/test/test.c
@@ -0,0 +1,485 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 "include.h"
+
+
+#define DEFAULT_DEBUG_LEVEL 0
+#define DEFAULT_THREADS_COUNT 1000
+
+
+typedef unsigned char bool_t;
+
+enum FLAG_OPT_enum {
+ FLAG_OPT_HELP = 0x01,
+ FLAG_OPT_VERSION = 0x02,
+};
+
+static struct {
+ uint8_t debug_level;
+ uint8_t opt_flags;
+ int runcount;
+ int runtime_ms;
+ int threads;
+ const char *ot_config;
+ const char *ot_plugin;
+ struct otc_tracer *ot_tracer;
+} cfg = {
+ .debug_level = DEFAULT_DEBUG_LEVEL,
+ .runtime_ms = -1,
+ .threads = DEFAULT_THREADS_COUNT,
+};
+
+enum OT_SPAN_enum {
+ OT_SPAN_ROOT = 0,
+ OP_SPAN_BAGGAGE,
+ OT_SPAN_PROP_TM,
+ OT_SPAN_PROP_HH,
+ OT_SPAN_PROP_BD,
+ OT_SPAN_MAX,
+};
+
+struct worker {
+ pthread_t thread;
+ int id;
+ struct otc_span *ot_span[OT_SPAN_MAX];
+ int ot_state;
+ uint64_t count;
+};
+
+static struct {
+ const char *name;
+ struct timeval start_time;
+ struct worker worker[8192];
+ volatile bool_t flag_run;
+} prg;
+
+
+uint8_t *cfg_debug_level = &(cfg.debug_level);
+
+
+/***
+ * NAME
+ * thread_id -
+ *
+ * ARGUMENTS
+ * This function takes no arguments.
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int thread_id(void)
+{
+ pthread_t id;
+ int i;
+
+ id = pthread_self();
+
+ for (i = 0; i < MIN(cfg.threads, TABLESIZE(prg.worker)); i++)
+ if (pthread_equal(prg.worker[i].thread, id))
+ return i + 1;
+
+ return 0;
+}
+
+
+/***
+ * NAME
+ * worker_finish_all_spans -
+ *
+ * ARGUMENTS
+ * worker -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static void worker_finish_all_spans(struct worker *worker)
+{
+ struct timespec ts;
+ int i;
+
+ OT_FUNC("%p", worker);
+
+ (void)clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ for (i = 0; i < TABLESIZE(worker->ot_span); i++)
+ if (_nNULL(worker->ot_span[i]))
+ ot_span_finish(worker->ot_span + i, &ts);
+}
+
+
+/***
+ * NAME
+ * worker_thread -
+ *
+ * ARGUMENTS
+ * data -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+__attribute__((noreturn)) static void *worker_thread(void *data)
+{
+ struct otc_text_map_writer tm_wr;
+ struct otc_http_headers_writer hh_wr;
+ struct otc_custom_carrier_writer cc_wr;
+ struct otc_span_context *context;
+ struct timeval now;
+ char name[16];
+ struct worker *worker = data;
+#ifdef DEBUG
+ int n = 0;
+#endif
+
+ OT_FUNC("%p", data);
+
+#ifdef __linux__
+ OT_DBG(WORKER, "Worker started, thread id: %" PRI_PTHREADT, syscall(SYS_gettid));
+#else
+ OT_DBG(WORKER, "Worker started, thread id: %" PRI_PTHREADT, worker->thread);
+#endif
+
+ (void)gettimeofday(&now, NULL);
+ (void)srandom(now.tv_usec);
+
+ (void)snprintf(name, sizeof(name), "test/wrk: %d", worker->id);
+ (void)pthread_setname_np(worker->thread, name);
+
+ while (!prg.flag_run) {
+ nsleep(0, 10000000);
+
+#ifdef DEBUG
+ n++;
+#endif
+ }
+
+ OT_DBG(DEBUG, "waiting loop count: %d", n);
+
+ for ( ; 1; worker->ot_state++) {
+ if (worker->ot_state != 0)
+ /* Do nothing. */;
+ else if ((cfg.runtime_ms > 0) && (TIMEVAL_DIFF_MS(&now, &(prg.start_time)) >= (uint)cfg.runtime_ms))
+ break;
+ else if ((cfg.runcount > 0) && ((uint)cfg.runcount <= worker->count))
+ break;
+
+ if (worker->ot_state == 0) {
+ worker->ot_span[OT_SPAN_ROOT] = ot_span_init(cfg.ot_tracer, "root span", -1, -1, NULL);
+ }
+ else if (worker->ot_state == 1) {
+ worker->ot_span[OP_SPAN_BAGGAGE] = ot_span_init(cfg.ot_tracer, "span #1", otc_span_reference_child_of, -1, worker->ot_span[OT_SPAN_ROOT]);
+ }
+ else if (worker->ot_state == 2) {
+ (void)ot_span_set_baggage(worker->ot_span[OP_SPAN_BAGGAGE], "baggage_1", "value_1", "baggage_2", "value_2", NULL);
+ }
+ else if (worker->ot_state == 3) {
+ if (_nNULL(context = ot_inject_text_map(cfg.ot_tracer, worker->ot_span[OP_SPAN_BAGGAGE], &tm_wr)))
+ context->destroy(&context);
+ }
+ else if (worker->ot_state == 4) {
+ struct otc_text_map_reader tm_rd;
+ struct otc_text_map *text_map = &(tm_wr.text_map);
+
+ if (_nNULL(context = ot_extract_text_map(cfg.ot_tracer, &tm_rd, text_map))) {
+ worker->ot_span[OT_SPAN_PROP_TM] = ot_span_init(cfg.ot_tracer, "text map propagation", otc_span_reference_child_of, context->idx, NULL);
+ context->destroy(&context);
+ }
+ otc_text_map_destroy(&text_map, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
+ }
+ else if (worker->ot_state == 5) {
+ struct otc_text_map *baggage = ot_span_baggage(worker->ot_span[OP_SPAN_BAGGAGE], "baggage_1", "baggage_2", NULL);
+
+ otc_text_map_destroy(&baggage, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
+ }
+ else if (worker->ot_state == 6) {
+ if (_nNULL(context = ot_inject_http_headers(cfg.ot_tracer, worker->ot_span[OP_SPAN_BAGGAGE], &hh_wr)))
+ context->destroy(&context);
+ }
+ else if (worker->ot_state == 7) {
+ struct otc_http_headers_reader hh_rd;
+ struct otc_text_map *text_map = &(hh_wr.text_map);
+
+ if (_nNULL(context = ot_extract_http_headers(cfg.ot_tracer, &hh_rd, text_map))) {
+ worker->ot_span[OT_SPAN_PROP_HH] = ot_span_init(cfg.ot_tracer, "http headers propagation", otc_span_reference_child_of, context->idx, NULL);
+ context->destroy(&context);
+ }
+ otc_text_map_destroy(&text_map, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
+ }
+ else if (worker->ot_state == 8) {
+ if (_nNULL(context = ot_inject_binary(cfg.ot_tracer, worker->ot_span[OP_SPAN_BAGGAGE], &cc_wr)))
+ context->destroy(&context);
+ }
+ else if (worker->ot_state == 9) {
+ struct otc_custom_carrier_reader cc_rd;
+ struct otc_binary_data *binary_data = &(cc_wr.binary_data);
+
+ if (_nNULL(context = ot_extract_binary(cfg.ot_tracer, &cc_rd, binary_data))) {
+ worker->ot_span[OT_SPAN_PROP_BD] = ot_span_init(cfg.ot_tracer, "binary data propagation", otc_span_reference_child_of, context->idx, NULL);
+ context->destroy(&context);
+ }
+ otc_binary_data_destroy(&binary_data);
+ }
+ else if (worker->ot_state == 10) {
+ (void)ot_span_tag(worker->ot_span[OT_SPAN_ROOT], "tag_1", OT_VARGS(string, "value_1"), "tag_2", OT_VARGS(string, "value_2"), NULL);
+ }
+ else if (worker->ot_state == 11) {
+ (void)ot_span_log_kv(worker->ot_span[OT_SPAN_PROP_TM], "log_1", "content_1", "log_2", "content_2", NULL);
+ }
+ else {
+ worker_finish_all_spans(worker);
+
+ worker->ot_state = -1;
+ worker->count++;
+ }
+
+ nsleep(0, ((random() % 100) + 1) * 10000);
+ (void)gettimeofday(&now, NULL);
+ }
+
+ pthread_exit(NULL);
+}
+
+
+/***
+ * NAME
+ * worker_run -
+ *
+ * ARGUMENTS
+ * This function takes no arguments.
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static int worker_run(void)
+{
+ struct timeval now;
+ char ot_infbuf[BUFSIZ];
+ uint64_t total_count = 0;
+ int i, num_threads = 0, retval = EX_OK;
+
+ OT_FUNC("");
+
+ (void)pthread_setname_np(pthread_self(), "test/wrk: main");
+
+ for (i = 0; i < cfg.threads; i++) {
+ prg.worker[i].id = i + 1;
+
+ if (pthread_create(&(prg.worker[i].thread), NULL, worker_thread, prg.worker + i) != 0)
+ (void)fprintf(stderr, "ERROR: Failed to start thread for worker %d: %m\n", prg.worker[i].id);
+ else
+ num_threads++;
+ }
+
+ prg.flag_run = 1;
+
+ (void)gettimeofday(&now, NULL);
+ OT_DBG(WORKER, "%d threads started in %llu ms", num_threads, TIMEVAL_DIFF_MS(&now, &(prg.start_time)));
+
+ for (i = 0; i < cfg.threads; i++) {
+ if (pthread_join(prg.worker[i].thread, NULL) != 0)
+ (void)fprintf(stderr, "ERROR: Failed to join worker thread %d: %m\n", prg.worker[i].id);
+ else
+ OT_LOG("worker %d count: %" PRIu64, i, prg.worker[i].count);
+
+ total_count += prg.worker[i].count;
+ }
+
+ OT_LOG("%d worker(s) total count: %" PRIu64, cfg.threads, total_count);
+
+ cfg.ot_tracer->close(cfg.ot_tracer);
+
+ otc_statistics(ot_infbuf, sizeof(ot_infbuf));
+ OT_LOG("OpenTracing statistics: %s", ot_infbuf);
+
+ return retval;
+}
+
+
+/***
+ * NAME
+ * usage -
+ *
+ * ARGUMENTS
+ * program_name -
+ * flag_verbose -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void usage(const char *program_name, bool_t flag_verbose)
+{
+ (void)printf("\nUsage: %s { -h --help }\n", program_name);
+ (void)printf(" %s { -V --version }\n", program_name);
+ (void)printf(" %s { [ -R --runcount=VALUE ] | [ -r --runtime=TIME ] } [OPTION]...\n\n", program_name);
+
+ if (flag_verbose) {
+ (void)printf("Options are:\n");
+ (void)printf(" -c, --config=FILE Specify the configuration for the used tracer.\n");
+#ifdef DEBUG
+ (void)printf(" -d, --debug=LEVEL Enable and specify the debug mode level (default: %d).\n", DEFAULT_DEBUG_LEVEL);
+#endif
+ (void)printf(" -h, --help Show this text.\n");
+ (void)printf(" -p, --plugin=FILE Specify the OpenTracing compatible plugin library.\n");
+ (void)printf(" -R, --runcount=VALUE Execute this program a certain number of passes (0 = unlimited).\n");
+ (void)printf(" -r, --runtime=TIME Run this program for a certain amount of time (ms, 0 = unlimited).\n");
+ (void)printf(" -t, --threads=VALUE Specify the number of threads (default: %d).\n", DEFAULT_THREADS_COUNT);
+ (void)printf(" -V, --version Show program version.\n\n");
+ (void)printf("Copyright 2020 HAProxy Technologies\n");
+ (void)printf("SPDX-License-Identifier: Apache-2.0\n\n");
+ } else {
+ (void)printf("For help type: %s -h\n\n", program_name);
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ static const struct option longopts[] = {
+ { "config", required_argument, NULL, 'c' },
+#ifdef DEBUG
+ { "debug", required_argument, NULL, 'd' },
+#endif
+ { "help", no_argument, NULL, 'h' },
+ { "plugin", required_argument, NULL, 'p' },
+ { "runcount", required_argument, NULL, 'R' },
+ { "runtime", required_argument, NULL, 'r' },
+ { "threads", required_argument, NULL, 't' },
+ { "version", no_argument, NULL, 'V' },
+ { NULL, 0, NULL, 0 }
+ };
+#ifdef OTC_DBG_MEM
+ static struct otc_dbg_mem_data dbg_mem_data[1000000];
+ struct otc_dbg_mem dbg_mem;
+#endif
+ const char *shortopts = "c:d:hp:R:r:t:V";
+ struct timeval now;
+ int c, longopts_idx = -1, retval = EX_OK;
+ bool_t flag_error = 0;
+ char ot_errbuf[BUFSIZ];
+
+ (void)gettimeofday(&(prg.start_time), NULL);
+
+ prg.name = basename(argv[0]);
+
+#ifdef OTC_DBG_MEM
+ retval = otc_dbg_mem_init(&dbg_mem, dbg_mem_data, TABLESIZE(dbg_mem_data), 0xff);
+ if (retval == -1) {
+ (void)fprintf(stderr, "ERROR: cannot initialize memory debugger\n");
+
+ return retval;
+ }
+#endif
+
+ while ((c = getopt_long(argc, argv, shortopts, longopts, &longopts_idx)) != EOF) {
+ if (c == 'c')
+ cfg.ot_config = optarg;
+#ifdef DEBUG
+ else if (c == 'd')
+ cfg.debug_level = atoi(optarg) & UINT8_C(0xff);
+#endif
+ else if (c == 'h')
+ cfg.opt_flags |= FLAG_OPT_HELP;
+ else if (c == 'p')
+ cfg.ot_plugin = optarg;
+ else if (c == 'R')
+ cfg.runcount = atoi(optarg);
+ else if (c == 'r')
+ cfg.runtime_ms = atoi(optarg);
+ else if (c == 't')
+ cfg.threads = atoi(optarg);
+ else if (c == 'V')
+ cfg.opt_flags |= FLAG_OPT_VERSION;
+ else
+ retval = EX_USAGE;
+ }
+
+ if (cfg.opt_flags & FLAG_OPT_HELP) {
+ usage(prg.name, 1);
+ }
+ else if (cfg.opt_flags & FLAG_OPT_VERSION) {
+ (void)printf("\n%s v%s [build %d] by %s, %s\n\n", prg.name, PACKAGE_VERSION, PACKAGE_BUILD, PACKAGE_AUTHOR, __DATE__);
+ }
+ else {
+ if ((cfg.runcount < 0) && (cfg.runtime_ms < 0)) {
+ (void)fprintf(stderr, "ERROR: run count/time value not set\n");
+ flag_error = 1;
+ }
+
+ if (!IN_RANGE(cfg.threads, 1, TABLESIZE(prg.worker))) {
+ (void)fprintf(stderr, "ERROR: invalid number of threads '%d'\n", cfg.threads);
+ flag_error = 1;
+ }
+
+ if (_NULL(cfg.ot_plugin) || _NULL(cfg.ot_config)) {
+ (void)fprintf(stderr, "ERROR: the OpenTracing configuration not set\n");
+ flag_error = 1;
+ }
+
+ if (flag_error)
+ usage(prg.name, 0);
+ }
+
+ cfg_debug_level = &(cfg.debug_level);
+
+ OT_FUNC("%d, %p", argc, argv);
+
+ if (flag_error || (cfg.opt_flags & (FLAG_OPT_HELP | FLAG_OPT_VERSION)))
+ return flag_error ? EX_USAGE : EX_OK;
+
+ if (_NULL(cfg.ot_tracer = otc_tracer_load(cfg.ot_plugin, ot_errbuf, sizeof(ot_errbuf)))) {
+ (void)fprintf(stderr, "ERROR: %s\n", (*ot_errbuf == '\0') ? "Unable to load tracing library" : ot_errbuf);
+
+ retval = EX_SOFTWARE;
+ }
+ else if (otc_tracer_start(cfg.ot_config, NULL, ot_errbuf, sizeof(ot_errbuf)) == -1) {
+ (void)fprintf(stderr, "ERROR: %s\n", (*ot_errbuf == '\0') ? "Unable to start tracing" : ot_errbuf);
+
+ retval = EX_SOFTWARE;
+ }
+ else {
+ retval = worker_run();
+ }
+
+ (void)gettimeofday(&now, NULL);
+ OT_DBG(INFO, "Program runtime: %llu ms", TIMEVAL_DIFF_MS(&now, &(prg.start_time)));
+
+ OTC_DBG_MEMINFO();
+
+ return retval;
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/test/util.c b/test/util.c
new file mode 100644
index 0000000..91c1af7
--- /dev/null
+++ b/test/util.c
@@ -0,0 +1,118 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 "include.h"
+
+
+/***
+ * NAME
+ * nsleep -
+ *
+ * ARGUMENTS
+ * sec -
+ * nsec -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void nsleep (uint sec, uint nsec)
+{
+ struct timespec ts1 = { sec, nsec }, ts2, *req = &ts1, *rem = &ts2;
+
+ while ((nanosleep (req, rem) == -1) && (errno == EINTR))
+ SWAP(req, rem);
+}
+
+
+/***
+ * NAME
+ * str_hex -
+ *
+ * ARGUMENTS
+ * data -
+ * size -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+const char *str_hex(const void *data, size_t size)
+{
+ static __thread char retbuf[BUFSIZ];
+ const uint8_t *ptr = data;
+ size_t i;
+
+ if (_NULL(data))
+ return "(null)";
+ else if (size == 0)
+ return "()";
+
+ for (i = 0, size <<= 1; (i < (sizeof(retbuf) - 2)) && (i < size); ptr++) {
+ retbuf[i++] = NIBBLE_TO_HEX(*ptr >> 4);
+ retbuf[i++] = NIBBLE_TO_HEX(*ptr & 0x0f);
+ }
+
+ retbuf[i] = '\0';
+
+ return retbuf;
+}
+
+
+/***
+ * NAME
+ * str_ctrl -
+ *
+ * ARGUMENTS
+ * data -
+ * size -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+const char *str_ctrl(const void *data, size_t size)
+{
+ static __thread char retbuf[BUFSIZ];
+ const uint8_t *ptr = data;
+ size_t i, n = 0;
+
+ if (_NULL(data))
+ return "(null)";
+ else if (size == 0)
+ return "()";
+
+ for (i = 0; (n < (sizeof(retbuf) - 1)) && (i < size); i++)
+ retbuf[n++] = IN_RANGE(ptr[i], 0x20, 0x7e) ? ptr[i] : '.';
+
+ retbuf[n] = '\0';
+
+ return retbuf;
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/test/util.h b/test/util.h
new file mode 100644
index 0000000..689a042
--- /dev/null
+++ b/test/util.h
@@ -0,0 +1,33 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * 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 TEST_UTIL_H
+#define TEST_UTIL_H
+
+int thread_id(void);
+void nsleep (uint sec, uint nsec);
+const char *str_hex(const void *data, size_t size);
+const char *str_ctrl(const void *data, size_t size);
+
+#endif /* TEST_UTIL_H */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */