├── .commit_docs.sh ├── .gitignore ├── .travis.yml ├── COPYRIGHT ├── ChangeLog ├── Doxyfile.in ├── DoxygenLayout.xml ├── LICENSE ├── Makefile.am ├── README.md ├── autogen.sh ├── configure.ac ├── fstrm ├── control.c ├── control.h ├── file.c ├── file.h ├── fstrm-private.h ├── fstrm.h ├── iothr.c ├── iothr.h ├── libfstrm.pc.in ├── libfstrm.sym ├── rdwr.c ├── rdwr.h ├── reader.c ├── reader.h ├── tcp_writer.c ├── tcp_writer.h ├── time.c ├── unix_writer.c ├── unix_writer.h ├── writer.c └── writer.h ├── libmy ├── .gitignore ├── COPYRIGHT ├── LICENSE ├── argv.c ├── argv.h ├── argv_loc.h ├── m4 │ ├── ax_compare_version.m4 │ ├── ax_define_dir.m4 │ ├── ax_prog_xsltproc.m4 │ ├── ax_pthread.m4 │ ├── ld-version-script.m4 │ ├── my_check_docbook_ns_xslt_min.m4 │ ├── my_code_coverage.m4 │ ├── my_pkg_config_files.m4 │ ├── pcap.m4 │ ├── pkg.m4 │ └── protobuf-c.m4 ├── my_alloc.h ├── my_memory_barrier.h ├── my_queue.h ├── my_queue_mb.c ├── my_queue_mutex.c ├── my_time.h ├── print_string.h ├── read_bytes.h ├── ubuf.h └── vector.h ├── m4 ├── .gitignore ├── ax_pthread.m4 ├── ld-version-script.m4 ├── my_code_coverage.m4 ├── my_pkg_config_files.m4 ├── pkg.m4 └── valgrind-tests.m4 ├── man ├── fstrm_capture.1 ├── fstrm_dump.1 └── fstrm_replay.1 ├── src ├── .gitignore ├── fstrm_capture.c ├── fstrm_dump.c └── fstrm_replay.c └── t ├── .gitignore ├── program_tests ├── test-fstrm.txt ├── test.fstrm ├── test_fstrm_dump.sh.in └── test_fstrm_replay.sh.in ├── run_test_fstrm_io_file.sh ├── run_test_fstrm_io_tcp.sh ├── run_test_fstrm_io_unix.sh ├── run_test_queue.sh ├── test_control.c ├── test_file_hello.c ├── test_fstrm_io_file.c ├── test_fstrm_io_sock.c ├── test_queue.c └── test_writer_hello.c /.commit_docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # from git-sh-setup.sh 4 | require_clean_work_tree () { 5 | git rev-parse --verify HEAD >/dev/null || exit 1 6 | git update-index -q --ignore-submodules --refresh 7 | err=0 8 | 9 | if ! git diff-files --quiet --ignore-submodules 10 | then 11 | echo >&2 "Cannot $0: You have unstaged changes." 12 | err=1 13 | fi 14 | 15 | if ! git diff-index --cached --quiet --ignore-submodules HEAD -- 16 | then 17 | if [ $err = 0 ] 18 | then 19 | echo >&2 "Cannot $0: Your index contains uncommitted changes." 20 | else 21 | echo >&2 "Additionally, your index contains uncommitted changes." 22 | fi 23 | err=1 24 | fi 25 | 26 | if [ $err = 1 ] 27 | then 28 | test -n "$2" && echo >&2 "$2" 29 | exit 1 30 | fi 31 | } 32 | 33 | require_clean_work_tree 34 | 35 | if ! which doxygen >/dev/null; then 36 | echo "Error: doxygen is required" 37 | exit 1 38 | fi 39 | 40 | DOXYGEN_VERSION="$(doxygen --version)" 41 | 42 | DOC_BRANCH="gh-pages" 43 | ORIG_BRANCH="$(git rev-parse --abbrev-ref HEAD)" 44 | ORIG_COMMIT="$(git describe --match=NeVeRmAtCh --always --abbrev=40 --dirty)" 45 | 46 | TOP="$(pwd)" 47 | export GIT_DIR="$TOP/.git" 48 | 49 | TMPDIR="$(mktemp --tmpdir=$TOP -d)" 50 | HTMLDIR="$TMPDIR/_build/html" 51 | INDEX_FILE="$GIT_DIR/index.${DOC_BRANCH}" 52 | 53 | rm -f "$INDEX_FILE" 54 | 55 | trap "{ cd $TOP; git checkout --force ${ORIG_BRANCH}; rm -f $INDEX_FILE; rm -rf $TMPDIR; }" EXIT 56 | 57 | cd "$TMPDIR" 58 | git reset --hard HEAD 59 | 60 | ./autogen.sh 61 | mkdir _build 62 | cd _build 63 | ../configure 64 | make html 65 | 66 | if ! git checkout "${DOC_BRANCH}"; then 67 | git checkout --orphan "${DOC_BRANCH}" 68 | fi 69 | 70 | touch "$HTMLDIR/.nojekyll" 71 | 72 | GIT_INDEX_FILE="$INDEX_FILE" GIT_WORK_TREE="$HTMLDIR" \ 73 | git add --no-ignore-removal . 74 | GIT_INDEX_FILE="$INDEX_FILE" GIT_WORK_TREE="$HTMLDIR" \ 75 | git commit -m "Rebuild html documentation from commit ${ORIG_COMMIT} using Doxygen ${DOXYGEN_VERSION}" 76 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .*swp 2 | *.gcda 3 | *.gcno 4 | *.la 5 | *.lo 6 | *.log 7 | *.o 8 | *.tar.gz 9 | *.trs 10 | .deps/ 11 | .dirstamp 12 | .libs/ 13 | /Doxyfile 14 | /aclocal.m4 15 | /autom4te.cache 16 | /build-aux 17 | /config.* 18 | /configure 19 | /html 20 | /libtool 21 | /stamp-h1 22 | /stamp-html 23 | Makefile 24 | Makefile.in 25 | TAGS 26 | fstrm/libfstrm.pc 27 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | os: 4 | - linux 5 | - osx 6 | 7 | matrix: 8 | include: 9 | - os: linux 10 | dist: trusty 11 | sudo: required 12 | 13 | before_install: 14 | # Linux 15 | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get update -qq; fi 16 | 17 | install: 18 | # Linux 19 | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get -qq install libevent-dev valgrind lcov; fi 20 | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo pip install cpp-coveralls; fi 21 | 22 | script: 23 | - ./autogen.sh 24 | - ./configure 25 | - make 26 | - make distcheck VERBOSE=1 27 | 28 | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then make clean; ./configure --enable-valgrind-tests && make distcheck VERBOSE=1 DISTCHECK_CONFIGURE_FLAGS="--enable-valgrind-tests"; fi 29 | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then make clean; ./configure --enable-code-coverage CFLAGS="" && make && make check; fi 30 | 31 | after_success: 32 | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then cpp-coveralls --build-root . --exclude libmy/ --exclude src/ --exclude t/ --exclude /usr/include; fi 33 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 by Farsight Security, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | fstrm (0.6.1) 2 | 3 | * fstrm_capture: ignore SIGPIPE, which will cause the 4 | interrupted connections to generate an EPIPE instead. 5 | 6 | * Fix truncation in snprintf calls in argument processing. 7 | 8 | * fstrm_capture: Fix output printf format. 9 | 10 | fstrm (0.6.0) 11 | 12 | * fstrm_capture: Perform output file rotation when a SIGUSR1 signal 13 | is received. This allows fstrm_capture's output file to be rotated 14 | by logrotate or a similar external utility. (Output rotation is 15 | suppressed if fstrm_capture is writing to stdout.) 16 | 17 | fstrm (0.5.0) 18 | 19 | * Change license to modern MIT license for compatibility with GPLv2 20 | software. 21 | 22 | * src/fstrm_replay.c: For OpenBSD and Posix portability include 23 | netinet/in.h and sys/socket.h to get struct sockaddr_in and the AF_* 24 | defines respectively. 25 | 26 | * Fix various compiler warnings. 27 | 28 | fstrm (0.4.0) 29 | 30 | * Added manual pages for fstrm_capture and fstrm_dump. 31 | 32 | * Added new tool, fstrm_replay, for replaying saved Frame Streams data 33 | to a socket connection. 34 | 35 | * Adds TCP support. Add tcp_writer to the core library which 36 | implements a bi-directional Frame Streams writer as a TCP socket 37 | client. Introduces new developer API: fstrm_tcp_writer_init, 38 | fstrm_tcp_writer_options_init, fstrm_tcp_writer_options_destroy, 39 | fstrm_tcp_writer_options_set_socket_address, and 40 | fstrm_tcp_writer_options_set_socket_port. 41 | 42 | * fstrm_capture: new options for reading from TCP socket. 43 | 44 | * fstrm_capture: add "-c" / "--connections" option to limit the 45 | number of concurrent connections it will accept. 46 | 47 | * fstrm_capture: add "-b / --buffer-size" option to set the read buffer 48 | size (effectively the maximum frame size) to a value other than the 49 | default 256 KiB. 50 | 51 | * fstrm_capture: skip oversize messages to fix stalled connections 52 | caused by messages larger than the read highwater mark of the input 53 | buffer. Discarded messages are logged for the purposes of tuning 54 | the input buffer size. 55 | 56 | * fstrm_capture: complete sending of FINISH frame before closing 57 | connection. 58 | 59 | * Various test additions and improvements. 60 | 61 | fstrm (0.3.2) 62 | 63 | * Accommodate systems without pthread_condattr_setclock (Issue #34) 64 | 65 | -- Chris Mikkelson Tue, 21 Mar 2017 19:15:11 -0500 66 | 67 | fstrm (0.3.1) 68 | 69 | * Add support for '-' as a filename for stdin/stdout (PR #28) 70 | 71 | * destroy condition variable and mutexes in fstrm_iothr_destroy() (PR #25) 72 | 73 | -- Chris Mikkelson Thu, 26 Jan 2017 16:05:06 -0600 74 | 75 | fstrm (0.3.0) 76 | 77 | * Output file rotation (Issue #22). 78 | 79 | * Build on OS X (Issue #21). 80 | 81 | * Change state properly in fstrm_writer_close() (Issue #18). 82 | 83 | * force output flush on sighup (Issue #12). 84 | 85 | -- Ben April Fri, 24 Jun 2016 22:29:56 -0500 86 | 87 | fstrm (0.2.0) 88 | 89 | * Fix fstrm_writer_open() to allow multiple opens (Issue #1). 90 | 91 | * New utility 'fstrm_capture', which requires libevent >= 2 (Issue #4). 92 | 93 | * Fix incorrect pthread_cond_timedwait() usage (Issue #5). 94 | 95 | * Backwards incompatible library API and protocol changes. 96 | 97 | * Doxygen documentation. 98 | 99 | -- Robert Edmonds Thu, 06 Nov 2014 19:19:44 -0500 100 | 101 | fstrm (0.1.0) 102 | 103 | * Initial release. 104 | 105 | -- Robert Edmonds Tue, 11 Feb 2014 20:00:25 -0500 106 | -------------------------------------------------------------------------------- /DoxygenLayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 by Farsight Security, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | AUTOMAKE_OPTIONS = parallel-tests 2 | 3 | bin_PROGRAMS = 4 | check_PROGRAMS = 5 | TESTS = 6 | EXTRA_DIST = 7 | CLEANFILES = 8 | ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} 9 | 10 | EXTRA_DIST += COPYRIGHT 11 | EXTRA_DIST += LICENSE 12 | EXTRA_DIST += README.md 13 | EXTRA_DIST += man/fstrm_capture.1 14 | EXTRA_DIST += man/fstrm_replay.1 15 | EXTRA_DIST += man/fstrm_dump.1 16 | 17 | AM_CPPFLAGS = \ 18 | -include $(top_builddir)/config.h \ 19 | -I${top_srcdir}/fstrm 20 | AM_CFLAGS = ${my_CFLAGS} 21 | AM_LDFLAGS = 22 | 23 | # 24 | ## 25 | ### code coverage 26 | ## 27 | # 28 | 29 | AM_CFLAGS += ${CODE_COVERAGE_CFLAGS} 30 | AM_LDFLAGS += ${CODE_COVERAGE_LDFLAGS} 31 | CODE_COVERAGE_LCOV_OPTIONS = --no-external 32 | CODE_COVERAGE_IGNORE_PATTERN = "$(abs_top_builddir)/t/*" 33 | @CODE_COVERAGE_RULES@ 34 | 35 | # 36 | ## 37 | ### library 38 | ## 39 | # 40 | 41 | LIBFSTRM_VERSION_INFO=1:0:1 42 | 43 | fstrm_libfstrm_la_DEPENDENCIES = \ 44 | $(top_srcdir)/fstrm/libfstrm.sym 45 | 46 | lib_LTLIBRARIES = fstrm/libfstrm.la 47 | 48 | include_HEADERS = fstrm/fstrm.h 49 | nobase_include_HEADERS = \ 50 | fstrm/control.h \ 51 | fstrm/iothr.h \ 52 | fstrm/file.h \ 53 | fstrm/rdwr.h \ 54 | fstrm/reader.h \ 55 | fstrm/tcp_writer.h \ 56 | fstrm/unix_writer.h \ 57 | fstrm/writer.h 58 | 59 | fstrm_libfstrm_la_SOURCES = \ 60 | fstrm/fstrm-private.h \ 61 | fstrm/control.c fstrm/control.h \ 62 | fstrm/file.c fstrm/file.h \ 63 | fstrm/iothr.c fstrm/iothr.h \ 64 | fstrm/rdwr.c fstrm/rdwr.h \ 65 | fstrm/reader.c fstrm/reader.h \ 66 | fstrm/tcp_writer.c fstrm/tcp_writer.h \ 67 | fstrm/time.c \ 68 | fstrm/unix_writer.c fstrm/unix_writer.h \ 69 | fstrm/writer.c fstrm/writer.h \ 70 | libmy/my_alloc.h \ 71 | libmy/my_memory_barrier.h \ 72 | libmy/my_queue.h \ 73 | libmy/my_queue_mb.c \ 74 | libmy/my_queue_mutex.c \ 75 | libmy/read_bytes.h \ 76 | libmy/ubuf.h \ 77 | libmy/vector.h 78 | 79 | EXTRA_DIST += \ 80 | libmy/my_queue_mb.c \ 81 | libmy/my_queue_mutex.c 82 | 83 | fstrm_libfstrm_la_CFLAGS = $(AM_CFLAGS) 84 | fstrm_libfstrm_la_LDFLAGS = $(AM_LDFLAGS) \ 85 | -version-info $(LIBFSTRM_VERSION_INFO) 86 | 87 | if HAVE_LD_VERSION_SCRIPT 88 | fstrm_libfstrm_la_LDFLAGS += \ 89 | -Wl,--version-script=$(top_srcdir)/fstrm/libfstrm.sym 90 | else 91 | fstrm_libfstrm_la_LDFLAGS += \ 92 | -export-symbols-regex "^(fstrm_[a-z]*)" 93 | endif 94 | EXTRA_DIST += fstrm/libfstrm.sym 95 | 96 | pkgconfig_DATA = ${LIBFSTRM_PC} 97 | CLEANFILES += ${LIBFSTRM_PC} 98 | EXTRA_DIST += fstrm/libfstrm.pc.in 99 | 100 | # 101 | ## 102 | ### tests 103 | ## 104 | # 105 | 106 | AM_TESTS_ENVIRONMENT = DIRNAME=$(top_builddir)/t; export DIRNAME; 107 | TESTS_ENVIRONMENT = $(AM_TESTS_ENVIRONMENT) 108 | LOG_COMPILER = $(VALGRIND) 109 | 110 | check_PROGRAMS += t/test_control 111 | t_test_control_SOURCES = \ 112 | t/test_control.c \ 113 | libmy/print_string.h 114 | t_test_control_LDADD = \ 115 | fstrm/libfstrm.la 116 | TESTS += t/test_control 117 | 118 | check_PROGRAMS += t/test_queue 119 | t_test_queue_SOURCES = \ 120 | t/test_queue.c \ 121 | libmy/my_queue.h \ 122 | libmy/my_queue_mb.c \ 123 | libmy/my_queue_mutex.c \ 124 | libmy/my_time.h 125 | t/run_test_queue.sh: t/test_queue 126 | TESTS += t/run_test_queue.sh 127 | EXTRA_DIST += t/run_test_queue.sh 128 | 129 | check_PROGRAMS += t/test_fstrm_io_file 130 | t_test_fstrm_io_file_SOURCES = \ 131 | t/test_fstrm_io_file.c \ 132 | libmy/my_alloc.h \ 133 | libmy/my_time.h \ 134 | libmy/ubuf.h \ 135 | libmy/vector.h 136 | t_test_fstrm_io_file_LDADD = \ 137 | fstrm/libfstrm.la 138 | t/run_test_fstrm_io_file.sh: t/test_fstrm_io_file 139 | TESTS += t/run_test_fstrm_io_file.sh 140 | EXTRA_DIST += t/run_test_fstrm_io_file.sh 141 | 142 | check_PROGRAMS += t/test_fstrm_io_sock 143 | t_test_fstrm_io_sock_SOURCES = \ 144 | t/test_fstrm_io_sock.c \ 145 | libmy/my_alloc.h \ 146 | libmy/my_time.h \ 147 | libmy/print_string.h \ 148 | libmy/ubuf.h \ 149 | libmy/vector.h 150 | t_test_fstrm_io_sock_LDADD = \ 151 | fstrm/libfstrm.la 152 | 153 | t/run_test_fstrm_io_unix.sh: t/test_fstrm_io_sock 154 | TESTS += t/run_test_fstrm_io_unix.sh 155 | EXTRA_DIST += t/run_test_fstrm_io_unix.sh 156 | 157 | t/run_test_fstrm_io_tcp.sh: t/test_fstrm_io_sock 158 | TESTS += t/run_test_fstrm_io_tcp.sh 159 | EXTRA_DIST += t/run_test_fstrm_io_tcp.sh 160 | 161 | check_PROGRAMS += t/test_writer_hello 162 | t_test_writer_hello_SOURCES = \ 163 | t/test_writer_hello.c \ 164 | libmy/my_alloc.h \ 165 | libmy/print_string.h 166 | t_test_writer_hello_LDADD = \ 167 | fstrm/libfstrm.la 168 | TESTS += t/test_writer_hello 169 | 170 | check_PROGRAMS += t/test_file_hello 171 | t_test_file_hello_SOURCES = \ 172 | t/test_file_hello.c \ 173 | libmy/print_string.h 174 | t_test_file_hello_LDADD = \ 175 | fstrm/libfstrm.la 176 | TESTS += t/test_file_hello 177 | 178 | # program tests 179 | EXTRA_DIST += \ 180 | t/program_tests/test_fstrm_dump.sh.in \ 181 | t/program_tests/test_fstrm_replay.sh.in \ 182 | t/program_tests/test.fstrm \ 183 | t/program_tests/test-fstrm.txt 184 | 185 | 186 | # 187 | ## 188 | ### programs 189 | ## 190 | # 191 | 192 | if BUILD_PROGRAMS 193 | bin_PROGRAMS += src/fstrm_dump 194 | src_fstrm_dump_SOURCES = \ 195 | src/fstrm_dump.c \ 196 | libmy/print_string.h 197 | src_fstrm_dump_LDADD = \ 198 | fstrm/libfstrm.la 199 | 200 | bin_PROGRAMS += src/fstrm_replay 201 | src_fstrm_replay_SOURCES = \ 202 | src/fstrm_replay.c \ 203 | libmy/argv.c libmy/argv.h libmy/argv_loc.h 204 | src_fstrm_replay_LDADD = \ 205 | fstrm/libfstrm.la 206 | 207 | bin_PROGRAMS += src/fstrm_capture 208 | src_fstrm_capture_CFLAGS = \ 209 | $(AM_CFLAGS) \ 210 | $(libevent_CFLAGS) 211 | src_fstrm_capture_SOURCES = \ 212 | src/fstrm_capture.c \ 213 | libmy/argv.c libmy/argv.h libmy/argv_loc.h 214 | src_fstrm_capture_LDADD = \ 215 | fstrm/libfstrm.la \ 216 | $(libevent_LIBS) 217 | 218 | man_MANS=man/fstrm_capture.1 man/fstrm_replay.1 man/fstrm_dump.1 219 | 220 | TESTS += t/program_tests/test_fstrm_dump.sh \ 221 | t/program_tests/test_fstrm_replay.sh 222 | endif 223 | 224 | # 225 | ## 226 | ### documentation 227 | ## 228 | # 229 | 230 | if HAVE_DOXYGEN 231 | stamp-html: $(DOXYGEN_INPUT_FILES) $(top_builddir)/Doxyfile $(top_srcdir)/DoxygenLayout.xml $(include_HEADERS) $(nobase_include_HEADERS) 232 | $(AM_V_GEN) $(DOXYGEN) 233 | @touch $@ 234 | html-local: stamp-html 235 | 236 | clean-local: 237 | rm -rf $(top_builddir)/html $(top_builddir)/stamp-html 238 | endif 239 | 240 | EXTRA_DIST += Doxyfile.in 241 | EXTRA_DIST += DoxygenLayout.xml 242 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/farsightsec/fstrm.png?branch=master)](https://travis-ci.org/farsightsec/fstrm) [![Coverage Status](https://coveralls.io/repos/farsightsec/fstrm/badge.png?branch=master)](https://coveralls.io/r/farsightsec/fstrm?branch=master) 2 | 3 | ## Overview 4 | 5 | This is `fstrm`, a C implementation of the Frame Streams data transport protocol. 6 | 7 | Frame Streams is a light weight, binary clean protocol that allows for the transport of arbitrarily encoded data payload sequences with minimal framing overhead -- just four bytes per data frame. Frame Streams does not specify an encoding format for data frames and can be used with any data serialization format that produces byte sequences, such as [Protocol Buffers], [XML], [JSON], [MessagePack], [YAML], etc. Frame Streams can be used as both a streaming transport over a reliable byte stream socket (TCP sockets, TLS connections, `AF_UNIX` sockets, etc.) for data in motion as well as a file format for data at rest. A "Content Type" header identifies the type of payload being carried over an individual Frame Stream and allows cooperating programs to determine how to interpret a given sequence of data payloads. 8 | 9 | `fstrm` is an optimized C implementation of Frame Streams that includes a fast, lockless circular queue implementation and exposes library interfaces for setting up a dedicated Frame Streams I/O thread and asynchronously submitting data frames for transport from worker threads. It was originally written to facilitate the addition of high speed binary logging to DNS servers written in C using the [dnstap] log format. 10 | 11 | [Protocol Buffers]: https://developers.google.com/protocol-buffers/ 12 | [XML]: http://www.w3.org/TR/xml11/ 13 | [JSON]: http://www.json.org/ 14 | [MessagePack]: http://msgpack.org/ 15 | [YAML]: http://www.yaml.org/ 16 | [dnstap]: http://dnstap.info/ 17 | 18 | 19 | ## Building 20 | 21 | `fstrm` requires a C99 compiler and the `pkg-config` utility to be installed. If building from a distribution tarball, the following command should build, test, and install `fstrm`: 22 | 23 | ./configure && make && make check && make install 24 | 25 | On platforms where the `pkg-config` utility is unavailable, .pc file installation can be disabled by passing `--without-pkgconfigdir` to `configure`. 26 | 27 | If building from a git checkout, the `autotools` (`autoconf`, `automake`, `libtool`) must also be installed, and the build system must be bootstrapped by running the `autogen.sh` script: 28 | 29 | ./autogen.sh && ./configure && make && make check && make install 30 | 31 | Reference programs `fstrm_capture`, `fstrm_dump`, and `fstrm_replay` are provided. In order to build `fstrm_capture`, the [libevent](http://libevent.org/) library must be installed. The option `--disable-programs` can be passed to `configure` to disable building these programs. 32 | 33 | ## Synopsis 34 | 35 | Include the `fstrm` header file from your C source code: 36 | 37 | #include 38 | 39 | Compile your C source code. Add the output of the following command to your compile flags: 40 | 41 | pkg-config --cflags libfstrm 42 | 43 | Link your C project against the `libfstrm` library. Add the output of the following command to your link flags: 44 | 45 | pkg-config --libs libfstrm 46 | 47 | If using autotools to build your C project, the `PKG_CHECK_MODULES` macro can be used to detect the presence of `libfstrm` by adding the following line to your `configure.ac` file: 48 | 49 | PKG_CHECK_MODULES([libfstrm], [libfstrm]) 50 | 51 | This will place compiler flags in the `libfstrm_CFLAGS` variable and linker flags in the `libfstrm_LIBS` variable. Read [more information here](https://www.flameeyes.eu/autotools-mythbuster/pkgconfig/pkg_check_modules.html) about the `PKG_CHECK_MODULES` macro. 52 | 53 | ## Documentation 54 | 55 | See the [online Doxygen documentation here](http://farsightsec.github.io/fstrm/) for a detailed reference. This documentation can be built from the source tree by running: 56 | 57 | make html 58 | 59 | ## Versioning 60 | 61 | `fstrm` follows the [Semantic Versioning Specification](http://semver.org/). 62 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec autoreconf -fvi 3 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ(2.64) 2 | 3 | AC_INIT([fstrm], 4 | [0.6.1], 5 | [https://github.com/farsightsec/fstrm/issues], 6 | [fstrm], 7 | [https://github.com/farsightsec/fstrm]) 8 | PACKAGE_DESCRIPTION="Frame Streams implementation in C" 9 | AC_SUBST(PACKAGE_DESCRIPTION) 10 | 11 | AC_CONFIG_SRCDIR([fstrm/fstrm.h]) 12 | AC_CONFIG_AUX_DIR([build-aux]) 13 | AM_INIT_AUTOMAKE([foreign 1.11 -Wall -Wno-portability silent-rules subdir-objects]) 14 | AC_PROG_CC_STDC 15 | AC_USE_SYSTEM_EXTENSIONS 16 | AC_SYS_LARGEFILE 17 | AC_CONFIG_MACRO_DIR([m4]) 18 | AM_SILENT_RULES([yes]) 19 | LT_INIT 20 | 21 | AC_CONFIG_HEADERS(config.h) 22 | AC_CONFIG_FILES([Makefile fstrm/libfstrm.pc]) 23 | 24 | AC_CONFIG_FILES([t/program_tests/test_fstrm_dump.sh], 25 | [chmod +x t/program_tests/test_fstrm_dump.sh]) 26 | 27 | AC_CONFIG_FILES([t/program_tests/test_fstrm_replay.sh], 28 | [chmod +x t/program_tests/test_fstrm_replay.sh]) 29 | 30 | my_PKG_CONFIG_FILES([LIBFSTRM_PC], [fstrm/libfstrm.pc]) 31 | 32 | my_CFLAGS="-Wall \ 33 | -Wmissing-declarations -Wmissing-prototypes \ 34 | -Wnested-externs -Wpointer-arith \ 35 | -Wpointer-arith -Wsign-compare -Wchar-subscripts \ 36 | -Wstrict-prototypes -Wshadow \ 37 | -Wformat-security" 38 | AC_SUBST([my_CFLAGS]) 39 | 40 | AC_CHECK_PROGS([DOXYGEN], [doxygen]) 41 | AM_CONDITIONAL([HAVE_DOXYGEN], 42 | [test -n "$DOXYGEN"]) 43 | AM_COND_IF([HAVE_DOXYGEN], 44 | [AC_CONFIG_FILES([Doxyfile]) 45 | DOXYGEN_INPUT="${srcdir}/fstrm" 46 | AC_SUBST(DOXYGEN_INPUT) 47 | ]) 48 | 49 | AX_PTHREAD([ 50 | LIBS="$PTHREAD_LIBS $LIBS" 51 | CFLAGS="$CFLAGS $PTHREAD_CFLAGS" 52 | CC="$PTHREAD_CC" 53 | ]) 54 | 55 | AC_SEARCH_LIBS([clock_gettime], [rt]) 56 | AC_CHECK_FUNCS([clock_gettime pthread_condattr_setclock]) 57 | 58 | AC_SEARCH_LIBS([socket], [socket]) 59 | 60 | AC_CHECK_DECLS([fread_unlocked, fwrite_unlocked, fflush_unlocked]) 61 | 62 | gl_LD_VERSION_SCRIPT 63 | 64 | gl_VALGRIND_TESTS 65 | 66 | MY_CODE_COVERAGE 67 | 68 | AC_ARG_ENABLE([programs], 69 | AS_HELP_STRING([--disable-programs], [Disable building fstrm utility programs])) 70 | AS_IF([test "x$enable_programs" != "xno"], [ 71 | PKG_CHECK_MODULES([libevent], [libevent >= 2]) 72 | ]) 73 | AM_CONDITIONAL([BUILD_PROGRAMS], [test "x$enable_programs" != "xno"]) 74 | 75 | AC_OUTPUT 76 | AC_MSG_RESULT([ 77 | $PACKAGE $VERSION 78 | 79 | compiler: ${CC} 80 | cflags: ${CFLAGS} 81 | ldflags: ${LDFLAGS} 82 | libs: ${LIBS} 83 | 84 | prefix: ${prefix} 85 | sysconfdir: ${sysconfdir} 86 | libdir: ${libdir} 87 | includedir: ${includedir} 88 | pkgconfigdir: ${pkgconfigdir} 89 | ]) 90 | -------------------------------------------------------------------------------- /fstrm/file.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, 2016 by Farsight Security, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #include "fstrm-private.h" 26 | 27 | struct fstrm_file_options { 28 | char *file_path; 29 | }; 30 | 31 | struct fstrm__file { 32 | FILE *fp; 33 | char *file_path; 34 | char file_mode[2]; 35 | }; 36 | 37 | struct fstrm_file_options * 38 | fstrm_file_options_init(void) 39 | { 40 | return my_calloc(1, sizeof(struct fstrm_file_options)); 41 | } 42 | 43 | void 44 | fstrm_file_options_destroy(struct fstrm_file_options **fopt) 45 | { 46 | if (*fopt != NULL) { 47 | my_free((*fopt)->file_path); 48 | my_free(*fopt); 49 | } 50 | } 51 | 52 | void 53 | fstrm_file_options_set_file_path(struct fstrm_file_options *fopt, 54 | const char *file_path) 55 | { 56 | my_free(fopt->file_path); 57 | if (file_path != NULL) 58 | fopt->file_path = my_strdup(file_path); 59 | } 60 | 61 | static fstrm_res 62 | fstrm__file_op_open(void *obj) 63 | { 64 | struct fstrm__file *f = obj; 65 | if (f->fp == NULL && f->file_path != NULL) { 66 | if (!strcmp(f->file_path, "-")) 67 | f->fp = f->file_mode[0] == 'r' ? stdin : stdout; 68 | else 69 | f->fp = fopen(f->file_path, f->file_mode); 70 | if (f->fp == NULL) 71 | return fstrm_res_failure; 72 | return fstrm_res_success; 73 | } 74 | return fstrm_res_failure; 75 | } 76 | 77 | static fstrm_res 78 | fstrm__file_op_close(void *obj) 79 | { 80 | struct fstrm__file *f = obj; 81 | if (f->fp != NULL) { 82 | FILE *fp = f->fp; 83 | f->fp = NULL; 84 | if (fclose(fp) != 0) 85 | return fstrm_res_failure; 86 | return fstrm_res_success; 87 | } 88 | return fstrm_res_failure; 89 | } 90 | 91 | static fstrm_res 92 | fstrm__file_op_read(void *obj, void *data, size_t count) 93 | { 94 | struct fstrm__file *f = obj; 95 | if (likely(f->fp != NULL)) { 96 | if (likely(fread(data, count, 1, f->fp) == 1)) { 97 | return fstrm_res_success; 98 | } else { 99 | if (ferror(f->fp)) 100 | return fstrm_res_failure; 101 | if (feof(f->fp)) 102 | return fstrm_res_stop; 103 | } 104 | } 105 | return fstrm_res_failure; 106 | } 107 | 108 | static fstrm_res 109 | fstrm__file_op_write(void *obj, const struct iovec *iov, int iovcnt) { 110 | struct fstrm__file *f = obj; 111 | if (unlikely(f->fp == NULL)) 112 | return fstrm_res_failure; 113 | for (int idx = 0; idx < iovcnt; idx++) { 114 | if (unlikely(fwrite(iov[idx].iov_base, iov[idx].iov_len, 1, f->fp) != 1)) { 115 | (void)fstrm__file_op_close(f); 116 | return fstrm_res_failure; 117 | } 118 | } 119 | return fstrm_res_success; 120 | } 121 | 122 | static fstrm_res 123 | fstrm__file_op_destroy(void *obj) 124 | { 125 | struct fstrm__file *f = obj; 126 | my_free(f->file_path); 127 | my_free(f); 128 | return fstrm_res_success; 129 | } 130 | 131 | static struct fstrm_rdwr * 132 | fstrm__file_init(const struct fstrm_file_options *fopt, const char file_mode) 133 | { 134 | struct fstrm__file *f; 135 | struct fstrm_rdwr *rdwr; 136 | 137 | if (fopt->file_path == NULL) 138 | return NULL; 139 | 140 | f = my_calloc(1, sizeof(*f)); 141 | f->file_path = my_strdup(fopt->file_path); 142 | f->file_mode[0] = file_mode; 143 | f->file_mode[1] = '\0'; 144 | 145 | rdwr = fstrm_rdwr_init(f); 146 | fstrm_rdwr_set_destroy(rdwr, fstrm__file_op_destroy); 147 | fstrm_rdwr_set_open(rdwr, fstrm__file_op_open); 148 | fstrm_rdwr_set_close(rdwr, fstrm__file_op_close); 149 | return rdwr; 150 | } 151 | 152 | struct fstrm_reader * 153 | fstrm_file_reader_init(const struct fstrm_file_options *fopt, 154 | const struct fstrm_reader_options *ropt) 155 | { 156 | struct fstrm_rdwr *rdwr = fstrm__file_init(fopt, 'r'); 157 | if (!rdwr) 158 | return NULL; 159 | fstrm_rdwr_set_read(rdwr, fstrm__file_op_read); 160 | return fstrm_reader_init(ropt, &rdwr); 161 | } 162 | 163 | struct fstrm_writer * 164 | fstrm_file_writer_init(const struct fstrm_file_options *fopt, 165 | const struct fstrm_writer_options *wopt) 166 | { 167 | struct fstrm_rdwr *rdwr = fstrm__file_init(fopt, 'w'); 168 | if (!rdwr) 169 | return NULL; 170 | fstrm_rdwr_set_write(rdwr, fstrm__file_op_write); 171 | return fstrm_writer_init(wopt, &rdwr); 172 | } 173 | -------------------------------------------------------------------------------- /fstrm/file.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 by Farsight Security, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #ifndef FSTRM_FILE_H 26 | #define FSTRM_FILE_H 27 | 28 | /** 29 | * \defgroup fstrm_file fstrm_file 30 | * 31 | * `fstrm_file` contains interfaces for opening \ref fstrm_reader or 32 | * \ref fstrm_writer objects that are backed by file I/O. 33 | * 34 | * @{ 35 | */ 36 | 37 | /** 38 | * Initialize an `fstrm_file_options` object, which is needed to configure the 39 | * file path to be opened by fstrm_file_reader_init() or 40 | * fstrm_file_writer_init(). 41 | * 42 | * \return 43 | * `fstrm_file_options` object. 44 | */ 45 | struct fstrm_file_options * 46 | fstrm_file_options_init(void); 47 | 48 | /** 49 | * Destroy an `fstrm_file_options` object. 50 | * 51 | * \param fopt 52 | * Pointer to `fstrm_file_options` object. 53 | */ 54 | void 55 | fstrm_file_options_destroy(struct fstrm_file_options **fopt); 56 | 57 | /** 58 | * Set the `file_path` option. This is a filesystem path to a regular file to be 59 | * opened for reading or writing. 60 | * 61 | * \param fopt 62 | * `fstrm_file_options` object. 63 | * \param file_path 64 | * The filesystem path for a regular file. 65 | */ 66 | void 67 | fstrm_file_options_set_file_path(struct fstrm_file_options *fopt, 68 | const char *file_path); 69 | 70 | /** 71 | * Open a file containing Frame Streams data for reading. 72 | * 73 | * \param fopt 74 | * `fstrm_file_options` object. Must be non-NULL, and have the `file_path` 75 | * option set. 76 | * \param ropt 77 | * `fstrm_reader_options` object. May be NULL, in which case default values 78 | * will be used. 79 | * 80 | * \return 81 | * `fstrm_reader` object. 82 | * \retval 83 | * NULL on failure. 84 | */ 85 | struct fstrm_reader * 86 | fstrm_file_reader_init(const struct fstrm_file_options *fopt, 87 | const struct fstrm_reader_options *ropt); 88 | 89 | /** 90 | * Open a file for writing Frame Streams data. The file will be truncated if it 91 | * already exists. 92 | * 93 | * \param fopt 94 | * `fstrm_file_options` object. Must be non-NULL, and have the `file_path` 95 | * option set. 96 | * \param wopt 97 | * `fstrm_writer_options` object. May be NULL, in which case default values 98 | * will be used. 99 | * 100 | * \return 101 | * `fstrm_writer` object. 102 | * \retval 103 | * NULL on failure. 104 | */ 105 | struct fstrm_writer * 106 | fstrm_file_writer_init(const struct fstrm_file_options *fopt, 107 | const struct fstrm_writer_options *wopt); 108 | 109 | /**@}*/ 110 | 111 | #endif /* FSTRM_FILE_H */ 112 | -------------------------------------------------------------------------------- /fstrm/fstrm-private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2016 by Farsight Security, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #ifndef FSTRM_PRIVATE_H 26 | #define FSTRM_PRIVATE_H 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include "fstrm.h" 43 | 44 | #include "libmy/my_alloc.h" 45 | #include "libmy/my_memory_barrier.h" 46 | #include "libmy/my_queue.h" 47 | #include "libmy/my_time.h" 48 | #include "libmy/read_bytes.h" 49 | #include "libmy/vector.h" 50 | 51 | #if defined(__GNUC__) 52 | # define likely(x) __builtin_expect(!!(x), 1) 53 | # define unlikely(x) __builtin_expect(!!(x), 0) 54 | # define warn_unused_result __attribute__ ((warn_unused_result)) 55 | #else 56 | # define likely(x) 57 | # define unlikely(x) 58 | # define warn_unused_result 59 | #endif 60 | 61 | #ifndef MSG_NOSIGNAL 62 | # define MSG_NOSIGNAL 0 63 | #endif 64 | 65 | #ifndef IOV_MAX 66 | # define IOV_MAX 1024 67 | #endif 68 | 69 | /* fs_buf, fs_bufvec */ 70 | 71 | typedef struct { 72 | size_t len; 73 | uint8_t *data; 74 | } fs_buf; 75 | 76 | VECTOR_GENERATE(fs_bufvec, fs_buf) 77 | 78 | /* buffer helpers */ 79 | 80 | warn_unused_result 81 | static inline bool 82 | fs_load_be32(const uint8_t **buf, size_t *len, uint32_t *val) 83 | { 84 | uint32_t be32_val; 85 | 86 | if (*len < sizeof(be32_val)) 87 | return false; 88 | memmove(&be32_val, *buf, sizeof(be32_val)); 89 | *val = ntohl(be32_val); 90 | *len -= sizeof(be32_val); 91 | *buf += sizeof(be32_val); 92 | return true; 93 | } 94 | 95 | warn_unused_result 96 | static inline bool 97 | fs_store_be32(uint8_t **buf, size_t *len, const uint32_t val) 98 | { 99 | uint32_t be32_val; 100 | 101 | be32_val = ntohl(val); 102 | if (*len < sizeof(be32_val)) 103 | return false; 104 | memmove(*buf, &be32_val, sizeof(be32_val)); 105 | *len -= sizeof(be32_val); 106 | *buf += sizeof(be32_val); 107 | return true; 108 | } 109 | 110 | warn_unused_result 111 | static inline bool 112 | fs_load_bytes(uint8_t *bytes, size_t len_bytes, 113 | const uint8_t **buf, size_t *len) 114 | { 115 | if (*len < len_bytes) 116 | return false; 117 | memmove(bytes, *buf, len_bytes); 118 | *len -= len_bytes; 119 | *buf += len_bytes; 120 | return true; 121 | } 122 | 123 | warn_unused_result 124 | static inline bool 125 | fs_store_bytes(uint8_t **buf, size_t *len, 126 | const uint8_t *bytes, size_t len_bytes) 127 | { 128 | if (*len < len_bytes) 129 | return false; 130 | memmove(*buf, bytes, len_bytes); 131 | *len -= len_bytes; 132 | *buf += len_bytes; 133 | return true; 134 | } 135 | 136 | /* rdwr */ 137 | 138 | struct fstrm_rdwr_ops { 139 | fstrm_rdwr_destroy_func destroy; 140 | fstrm_rdwr_open_func open; 141 | fstrm_rdwr_close_func close; 142 | fstrm_rdwr_read_func read; 143 | fstrm_rdwr_write_func write; 144 | }; 145 | 146 | struct fstrm_rdwr { 147 | struct fstrm_rdwr_ops ops; 148 | void *obj; 149 | bool opened; 150 | }; 151 | 152 | fstrm_res 153 | fstrm__rdwr_read_control_frame(struct fstrm_rdwr *, 154 | struct fstrm_control *, 155 | fstrm_control_type *, 156 | const bool with_escape); 157 | 158 | fstrm_res 159 | fstrm__rdwr_read_control(struct fstrm_rdwr *, 160 | struct fstrm_control **, 161 | fstrm_control_type wanted_type); 162 | 163 | fstrm_res 164 | fstrm__rdwr_write_control_frame(struct fstrm_rdwr *, 165 | const struct fstrm_control *); 166 | 167 | fstrm_res 168 | fstrm__rdwr_write_control(struct fstrm_rdwr *, 169 | fstrm_control_type type, 170 | const fs_buf *content_type); 171 | 172 | /* time */ 173 | 174 | #if HAVE_CLOCK_GETTIME 175 | bool fstrm__get_best_monotonic_clock_gettime(clockid_t *); 176 | 177 | bool fstrm__get_best_monotonic_clock_pthread(clockid_t *); 178 | 179 | bool fstrm__get_best_monotonic_clocks(clockid_t *clkid_gettime, 180 | clockid_t *clkid_pthread, 181 | char **errstr_out); 182 | #endif 183 | 184 | /* queue */ 185 | 186 | #ifdef MY_HAVE_MEMORY_BARRIERS 187 | extern const struct my_queue_ops my_queue_mb_ops; 188 | #endif 189 | 190 | extern const struct my_queue_ops my_queue_mutex_ops; 191 | 192 | #endif /* FSTRM_PRIVATE_H */ 193 | -------------------------------------------------------------------------------- /fstrm/libfstrm.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: libfstrm 7 | Description: FrameStream C library 8 | Version: @VERSION@ 9 | Libs: -L${libdir} -lfstrm 10 | Libs.private: 11 | Cflags: -I${includedir} 12 | -------------------------------------------------------------------------------- /fstrm/libfstrm.sym: -------------------------------------------------------------------------------- 1 | LIBFSTRM_0.2.0 { 2 | global: 3 | fstrm_control_add_field_content_type; 4 | fstrm_control_decode; 5 | fstrm_control_destroy; 6 | fstrm_control_encode; 7 | fstrm_control_encoded_size; 8 | fstrm_control_field_type_to_str; 9 | fstrm_control_get_field_content_type; 10 | fstrm_control_get_num_field_content_type; 11 | fstrm_control_get_type; 12 | fstrm_control_init; 13 | fstrm_control_match_field_content_type; 14 | fstrm_control_reset; 15 | fstrm_control_set_type; 16 | fstrm_control_type_to_str; 17 | fstrm_file_options_destroy; 18 | fstrm_file_options_init; 19 | fstrm_file_options_set_file_path; 20 | fstrm_file_reader_init; 21 | fstrm_file_writer_init; 22 | fstrm_free_wrapper; 23 | fstrm_iothr_destroy; 24 | fstrm_iothr_get_input_queue; 25 | fstrm_iothr_get_input_queue_idx; 26 | fstrm_iothr_init; 27 | fstrm_iothr_options_destroy; 28 | fstrm_iothr_options_init; 29 | fstrm_iothr_options_set_buffer_hint; 30 | fstrm_iothr_options_set_flush_timeout; 31 | fstrm_iothr_options_set_input_queue_size; 32 | fstrm_iothr_options_set_num_input_queues; 33 | fstrm_iothr_options_set_output_queue_size; 34 | fstrm_iothr_options_set_queue_model; 35 | fstrm_iothr_options_set_queue_notify_threshold; 36 | fstrm_iothr_options_set_reopen_interval; 37 | fstrm_iothr_submit; 38 | fstrm_rdwr_close; 39 | fstrm_rdwr_destroy; 40 | fstrm_rdwr_init; 41 | fstrm_rdwr_open; 42 | fstrm_rdwr_read; 43 | fstrm_rdwr_set_close; 44 | fstrm_rdwr_set_destroy; 45 | fstrm_rdwr_set_open; 46 | fstrm_rdwr_set_read; 47 | fstrm_rdwr_set_write; 48 | fstrm_rdwr_write; 49 | fstrm_reader_close; 50 | fstrm_reader_destroy; 51 | fstrm_reader_get_control; 52 | fstrm_reader_init; 53 | fstrm_reader_open; 54 | fstrm_reader_options_add_content_type; 55 | fstrm_reader_options_destroy; 56 | fstrm_reader_options_init; 57 | fstrm_reader_options_set_max_frame_size; 58 | fstrm_reader_read; 59 | fstrm_unix_writer_init; 60 | fstrm_unix_writer_options_destroy; 61 | fstrm_unix_writer_options_init; 62 | fstrm_unix_writer_options_set_socket_path; 63 | fstrm_writer_close; 64 | fstrm_writer_destroy; 65 | fstrm_writer_get_control; 66 | fstrm_writer_init; 67 | fstrm_writer_open; 68 | fstrm_writer_options_add_content_type; 69 | fstrm_writer_options_destroy; 70 | fstrm_writer_options_init; 71 | fstrm_writer_write; 72 | fstrm_writer_writev; 73 | local: 74 | *; 75 | }; 76 | 77 | LIBFSTRM_0.4.0 { 78 | global: 79 | fstrm_tcp_writer_options_init; 80 | fstrm_tcp_writer_options_destroy; 81 | fstrm_tcp_writer_options_set_socket_address; 82 | fstrm_tcp_writer_options_set_socket_port; 83 | fstrm_tcp_writer_init; 84 | } LIBFSTRM_0.2.0; 85 | -------------------------------------------------------------------------------- /fstrm/rdwr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 by Farsight Security, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #include "fstrm-private.h" 26 | 27 | struct fstrm_rdwr * 28 | fstrm_rdwr_init(void *obj) 29 | { 30 | struct fstrm_rdwr *rdwr; 31 | rdwr = my_calloc(1, sizeof(*rdwr)); 32 | rdwr->obj = obj; 33 | return rdwr; 34 | } 35 | 36 | fstrm_res 37 | fstrm_rdwr_destroy(struct fstrm_rdwr **rdwr) 38 | { 39 | fstrm_res res = fstrm_res_success; 40 | if (*rdwr != NULL) { 41 | if ((*rdwr)->ops.destroy != NULL) 42 | res = (*rdwr)->ops.destroy((*rdwr)->obj); 43 | my_free(*rdwr); 44 | } 45 | return res; 46 | } 47 | 48 | fstrm_res 49 | fstrm_rdwr_open(struct fstrm_rdwr *rdwr) 50 | { 51 | fstrm_res res; 52 | if (unlikely(rdwr->ops.open == NULL)) 53 | return fstrm_res_failure; 54 | res = rdwr->ops.open(rdwr->obj); 55 | if (res == fstrm_res_success) 56 | rdwr->opened = true; 57 | return res; 58 | } 59 | 60 | fstrm_res 61 | fstrm_rdwr_close(struct fstrm_rdwr *rdwr) 62 | { 63 | if (unlikely(rdwr->ops.close == NULL)) 64 | return fstrm_res_failure; 65 | if (rdwr->opened) { 66 | rdwr->opened = false; 67 | return rdwr->ops.close(rdwr->obj); 68 | } 69 | return fstrm_res_success; 70 | } 71 | 72 | fstrm_res 73 | fstrm_rdwr_read(struct fstrm_rdwr *rdwr, void *data, size_t count) 74 | { 75 | fstrm_res res; 76 | 77 | /* If the rdwr is not opened, it cannot be read from. */ 78 | if (unlikely(!rdwr->opened)) 79 | return fstrm_res_failure; 80 | 81 | /* This should never be called on a rdwr without a read method. */ 82 | if (unlikely(rdwr->ops.read == NULL)) 83 | return fstrm_res_failure; 84 | 85 | /* 86 | * Invoke the rdwr's read method. If this fails we need to clean up by 87 | * invoking the close method. 88 | */ 89 | res = rdwr->ops.read(rdwr->obj, data, count); 90 | if (unlikely(res != fstrm_res_success)) 91 | (void)fstrm_rdwr_close(rdwr); 92 | return res; 93 | } 94 | 95 | fstrm_res 96 | fstrm_rdwr_write(struct fstrm_rdwr *rdwr, const struct iovec *iov, int iovcnt) 97 | { 98 | fstrm_res res; 99 | 100 | /* If the rdwr is not opened, it cannot be written to. */ 101 | if (unlikely(!rdwr->opened)) 102 | return fstrm_res_failure; 103 | 104 | /* This should never be called on a rdwr without a write method. */ 105 | if (unlikely(rdwr->ops.write == NULL)) 106 | return fstrm_res_failure; 107 | 108 | /* 109 | * Invoke the rdwr's write method. If this fails we need to clean up by 110 | * invoking the close method. 111 | */ 112 | res = rdwr->ops.write(rdwr->obj, iov, iovcnt); 113 | if (unlikely(res != fstrm_res_success)) 114 | (void)fstrm_rdwr_close(rdwr); 115 | return res; 116 | } 117 | 118 | void 119 | fstrm_rdwr_set_destroy(struct fstrm_rdwr *rdwr, 120 | fstrm_rdwr_destroy_func fn) 121 | { 122 | rdwr->ops.destroy = fn; 123 | } 124 | 125 | void 126 | fstrm_rdwr_set_open(struct fstrm_rdwr *rdwr, 127 | fstrm_rdwr_open_func fn) 128 | { 129 | rdwr->ops.open = fn; 130 | } 131 | 132 | void 133 | fstrm_rdwr_set_close(struct fstrm_rdwr *rdwr, 134 | fstrm_rdwr_close_func fn) 135 | { 136 | rdwr->ops.close = fn; 137 | } 138 | 139 | void 140 | fstrm_rdwr_set_read(struct fstrm_rdwr *rdwr, 141 | fstrm_rdwr_read_func fn) 142 | { 143 | rdwr->ops.read = fn; 144 | } 145 | 146 | void 147 | fstrm_rdwr_set_write(struct fstrm_rdwr *rdwr, 148 | fstrm_rdwr_write_func fn) 149 | { 150 | rdwr->ops.write = fn; 151 | } 152 | 153 | fstrm_res 154 | fstrm__rdwr_read_control_frame(struct fstrm_rdwr *rdwr, 155 | struct fstrm_control *control, 156 | fstrm_control_type *type, 157 | const bool with_escape) 158 | { 159 | const uint32_t flags = 0; 160 | uint32_t tmp; 161 | fstrm_res res; 162 | 163 | if (with_escape) { 164 | /* Read the escape sequence. */ 165 | res = fstrm_rdwr_read(rdwr, &tmp, sizeof(tmp)); 166 | if (res != fstrm_res_success) 167 | return res; 168 | if (ntohl(tmp) != 0) 169 | return fstrm_res_failure; 170 | } 171 | 172 | /* Read the control frame length. */ 173 | res = fstrm_rdwr_read(rdwr, &tmp, sizeof(tmp)); 174 | if (res != fstrm_res_success) 175 | return res; 176 | const size_t len_control_frame = ntohl(tmp); 177 | 178 | /* Sanity check the control frame length. */ 179 | if (len_control_frame > FSTRM_CONTROL_FRAME_LENGTH_MAX) 180 | return fstrm_res_failure; 181 | 182 | /* Read the control frame. */ 183 | uint8_t control_frame[len_control_frame]; 184 | res = fstrm_rdwr_read(rdwr, control_frame, sizeof(control_frame)); 185 | if (res != fstrm_res_success) 186 | return res; 187 | 188 | /* Decode the control frame. */ 189 | assert(control != NULL); 190 | res = fstrm_control_decode(control, 191 | control_frame, len_control_frame, 192 | flags); 193 | if (res != fstrm_res_success) 194 | return res; 195 | 196 | /* Get the type. */ 197 | if (type != NULL) { 198 | res = fstrm_control_get_type(control, type); 199 | if (res != fstrm_res_success) 200 | return res; 201 | } 202 | 203 | return fstrm_res_success; 204 | } 205 | 206 | fstrm_res 207 | fstrm__rdwr_read_control(struct fstrm_rdwr *rdwr, 208 | struct fstrm_control **control, 209 | fstrm_control_type wanted_type) 210 | { 211 | fstrm_res res; 212 | fstrm_control_type actual_type; 213 | 214 | if (*control == NULL) 215 | *control = fstrm_control_init(); 216 | 217 | res = fstrm__rdwr_read_control_frame(rdwr, *control, &actual_type, true); 218 | if (res != fstrm_res_success) 219 | return res; 220 | 221 | if (actual_type != wanted_type) 222 | return fstrm_res_failure; 223 | 224 | return fstrm_res_success; 225 | } 226 | 227 | fstrm_res 228 | fstrm__rdwr_write_control_frame(struct fstrm_rdwr *rdwr, 229 | const struct fstrm_control *control) 230 | { 231 | const uint32_t flags = FSTRM_CONTROL_FLAG_WITH_HEADER; 232 | size_t len_control_frame = 0; 233 | fstrm_res res; 234 | 235 | /* Calculate the length of the control frame. */ 236 | res = fstrm_control_encoded_size(control, &len_control_frame, flags); 237 | if (res != fstrm_res_success) 238 | return res; 239 | 240 | /* Serialize the control frame. */ 241 | uint8_t control_frame[len_control_frame]; 242 | res = fstrm_control_encode(control, control_frame, &len_control_frame, flags); 243 | if (res != fstrm_res_success) 244 | return res; 245 | 246 | /* Write the control frame. */ 247 | struct iovec control_iov = { 248 | .iov_base = (void *) &control_frame[0], 249 | .iov_len = len_control_frame, 250 | }; 251 | return fstrm_rdwr_write(rdwr, &control_iov, 1); 252 | } 253 | 254 | fstrm_res 255 | fstrm__rdwr_write_control(struct fstrm_rdwr *rdwr, 256 | fstrm_control_type type, 257 | const fs_buf *content_type) 258 | { 259 | fstrm_res res = fstrm_res_failure; 260 | struct fstrm_control *control = fstrm_control_init(); 261 | 262 | res = fstrm_control_set_type(control, type); 263 | if (res != fstrm_res_success) 264 | goto out; 265 | 266 | if (content_type != NULL && content_type->data != NULL) { 267 | res = fstrm_control_add_field_content_type(control, 268 | content_type->data, content_type->len); 269 | if (res != fstrm_res_success) 270 | goto out; 271 | } 272 | 273 | res = fstrm__rdwr_write_control_frame(rdwr, control); 274 | out: 275 | fstrm_control_destroy(&control); 276 | return res; 277 | } 278 | -------------------------------------------------------------------------------- /fstrm/reader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 by Farsight Security, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #ifndef FSTRM_READER_H 26 | #define FSTRM_READER_H 27 | 28 | /** 29 | * \defgroup fstrm_reader fstrm_reader 30 | * 31 | * `fstrm_reader` is an interface for reading Frame Streams data from a byte 32 | * stream. The underlying byte stream I/O operations are abstracted by the 33 | * \ref fstrm_rdwr interface. Thus, the `fstrm_reader` interface can be used to 34 | * read Frame Streams data from any source whose read/write operations are 35 | * wrapped by an `fstrm_rdwr` object. 36 | * 37 | * Some basic `fstrm_reader` implementations are already provided in the `fstrm` 38 | * library. See fstrm_file_reader_init() to create an `fstrm_reader` object that 39 | * reads Frame Streams data from a regular file. 40 | * 41 | * @{ 42 | */ 43 | 44 | /** 45 | * The default `max_frame_size` value. 46 | */ 47 | #define FSTRM_READER_MAX_FRAME_SIZE_DEFAULT 1048576 48 | 49 | /** 50 | * Initialize an `fstrm_reader_options` object. 51 | * 52 | * \return 53 | * `fstrm_reader_options` object. 54 | */ 55 | struct fstrm_reader_options * 56 | fstrm_reader_options_init(void); 57 | 58 | /** 59 | * Destroy an `fstrm_reader_options` object. 60 | * 61 | * \param ropt 62 | * Pointer to `fstrm_reader_options` object. 63 | */ 64 | void 65 | fstrm_reader_options_destroy( 66 | struct fstrm_reader_options **ropt); 67 | 68 | /** 69 | * Add a "Content Type" value to the set of content types accepted by the 70 | * `fstrm_reader`. This function makes a copy of the provided string. This 71 | * function may be called multiple times, in which case multiple "Content Type" 72 | * values will be accepted by the reader. 73 | * 74 | * If the reader has no content types set, it will accept any content type. 75 | * 76 | * \param ropt 77 | * `fstrm_reader_options` object. 78 | * \param content_type 79 | * The "Content Type" string to copy. Note that this string is not 80 | * NUL-terminated and may contain embedded NULs. 81 | * \param len_content_type 82 | * The number of bytes in `content_type`. 83 | * 84 | * \retval #fstrm_res_success 85 | * The "Content Type" field was successfully added. 86 | * \retval #fstrm_res_failure 87 | * The "Content Type" string is too long. 88 | */ 89 | fstrm_res 90 | fstrm_reader_options_add_content_type( 91 | struct fstrm_reader_options *ropt, 92 | const void *content_type, 93 | size_t len_content_type); 94 | 95 | /** 96 | * Set the maximum frame size that the reader is willing to accept. This 97 | * enforces an upper limit on the amount of memory used to buffer incoming data 98 | * from the reader's byte stream. 99 | * 100 | * If this option is not set, it defaults to 101 | * #FSTRM_READER_MAX_FRAME_SIZE_DEFAULT. 102 | * 103 | * \param ropt 104 | * `fstrm_reader_options` object. 105 | * \param max_frame_size 106 | * The maximum frame size value. 107 | * 108 | * \retval #fstrm_res_success 109 | * The `max_frame_size` value was successfully set. 110 | * \retval #fstrm_res_failure 111 | * The `max_frame_size` value was too large or too small. 112 | */ 113 | fstrm_res 114 | fstrm_reader_options_set_max_frame_size( 115 | struct fstrm_reader_options *ropt, 116 | size_t max_frame_size); 117 | 118 | /** 119 | * Initialize a new `fstrm_reader` object based on an underlying `fstrm_rdwr` 120 | * object and an `fstrm_reader_options` object. 121 | * 122 | * The underlying `fstrm_rdwr` object MUST have a `read` method. It MAY 123 | * optionally have a `write` method, in which case the stream will be treated as 124 | * a bi-directional, handshaked stream. Otherwise, if there is no `write` method 125 | * the stream will be treated as a uni-directional stream. 126 | * 127 | * This function is useful for implementing functions that return new types of 128 | * `fstrm_reader` objects, such as fstrm_file_reader_init(). 129 | * 130 | * After a successful call to this function, the ownership of the `fstrm_rdwr` 131 | * object passes from the caller to the `fstrm_reader` object. The caller 132 | * should perform no further calls on the `fstrm_rdwr` object. The `fstrm_rdwr` 133 | * object will be cleaned up on a call to fstrm_reader_destroy(). 134 | * 135 | * \param ropt 136 | * `fstrm_reader_options` object. May be NULL, in which case default values 137 | * will be used. 138 | * 139 | * \param rdwr 140 | * Pointer to `fstrm_rdwr` object. Must be non-NULL. The `fstrm_rdwr` 141 | * object must have a `read` method, and may optionally have a `write` 142 | * method. 143 | * 144 | * \return 145 | * `fstrm_reader` object. 146 | * \retval 147 | * NULL on failure. 148 | */ 149 | struct fstrm_reader * 150 | fstrm_reader_init( 151 | const struct fstrm_reader_options *ropt, 152 | struct fstrm_rdwr **rdwr); 153 | 154 | /** 155 | * Destroy an `fstrm_reader` object. This implicitly calls fstrm_reader_close() 156 | * if necessary. 157 | * 158 | * \param r 159 | * Pointer to `fstrm_reader` object. 160 | * 161 | * \retval #fstrm_res_success 162 | * \retval #fstrm_res_failure 163 | */ 164 | fstrm_res 165 | fstrm_reader_destroy(struct fstrm_reader **r); 166 | 167 | /** 168 | * Open an `fstrm_reader` object and prepare it to read data. 169 | * 170 | * This checks that the content type in the byte stream, if specified, matches 171 | * one of the content types specified in the `fstrm_reader_options` object used 172 | * to initialize the `fstrm_reader` object. 173 | * 174 | * This function may fail if there was an underlying problem opening the input 175 | * stream. 176 | * 177 | * \param r 178 | * `fstrm_reader` object. 179 | * 180 | * \retval #fstrm_res_success 181 | * \retval #fstrm_res_failure 182 | */ 183 | fstrm_res 184 | fstrm_reader_open(struct fstrm_reader *r); 185 | 186 | /** 187 | * Close an `fstrm_reader` object. Once it has been closed, no data frames may 188 | * subsequently be read. 189 | * 190 | * Calling this function is optional; it may be implicitly invoked by a call to 191 | * fstrm_reader_destroy(). 192 | * 193 | * \param r 194 | * `fstrm_reader` object. 195 | * 196 | * \retval #fstrm_res_success 197 | * \retval #fstrm_res_failure 198 | */ 199 | fstrm_res 200 | fstrm_reader_close(struct fstrm_reader *r); 201 | 202 | /** 203 | * Read a data frame from an `fstrm_reader` object. This frame is held in an 204 | * internal buffer owned by the `fstrm_reader` object and should not be modified 205 | * by the caller. The contents of this buffer will be overwritten by a 206 | * subsequent call to fstrm_reader_read(). 207 | * 208 | * This function implicitly calls fstrm_reader_open() if necessary. 209 | * 210 | * \param r 211 | * `fstrm_reader` object. 212 | * \param[out] data 213 | * Pointer to buffer containing the data frame payload. 214 | * \param[out] len_data 215 | * The number of bytes available in `data`. 216 | * 217 | * \retval #fstrm_res_success 218 | * A data frame was successfully read. 219 | * \retval #fstrm_res_stop 220 | * The end of the stream has been reached. 221 | * \retval #fstrm_res_failure 222 | */ 223 | fstrm_res 224 | fstrm_reader_read( 225 | struct fstrm_reader *r, 226 | const uint8_t **data, 227 | size_t *len_data); 228 | 229 | /** 230 | * Obtain a pointer to an `fstrm_control` object used during processing. Objects 231 | * returned by this function are owned by the `fstrm_reader` object and must not 232 | * be modified by the caller. After a call to fstrm_reader_destroy() these 233 | * pointers will no longer be valid. 234 | * 235 | * For example, this function can be used to obtain a pointer to the START 236 | * control frame, which can be queried to see which "Content Type" was 237 | * negotiated during the opening of the reader. 238 | * 239 | * This function implicitly calls fstrm_reader_open() if necessary. 240 | * 241 | * \param r 242 | * `fstrm_reader` object. 243 | * \param type 244 | * Which control frame to return. 245 | * \param[out] control 246 | * The `fstrm_control` object. 247 | * 248 | * \retval #fstrm_res_success 249 | * If an `fstrm_control` object was returned. 250 | * \retval #fstrm_res_failure 251 | */ 252 | fstrm_res 253 | fstrm_reader_get_control( 254 | struct fstrm_reader *r, 255 | fstrm_control_type type, 256 | const struct fstrm_control **control); 257 | 258 | /**@}*/ 259 | 260 | #endif /* FSTRM_READER_H */ 261 | -------------------------------------------------------------------------------- /fstrm/tcp_writer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014, 2018 by Farsight Security, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "fstrm-private.h" 33 | 34 | struct fstrm_tcp_writer_options { 35 | char *socket_address; 36 | char *socket_port; 37 | }; 38 | 39 | struct fstrm__tcp_writer { 40 | bool connected; 41 | int fd; 42 | struct sockaddr_storage ss; 43 | socklen_t ss_len; 44 | }; 45 | 46 | struct fstrm_tcp_writer_options * 47 | fstrm_tcp_writer_options_init(void) 48 | { 49 | return my_calloc(1, sizeof(struct fstrm_tcp_writer_options)); 50 | } 51 | 52 | void 53 | fstrm_tcp_writer_options_destroy(struct fstrm_tcp_writer_options **twopt) 54 | { 55 | if (*twopt != NULL) { 56 | my_free((*twopt)->socket_address); 57 | my_free((*twopt)->socket_port); 58 | my_free(*twopt); 59 | } 60 | } 61 | 62 | void 63 | fstrm_tcp_writer_options_set_socket_address( 64 | struct fstrm_tcp_writer_options *twopt, 65 | const char *socket_address) 66 | { 67 | my_free(twopt->socket_address); 68 | if (socket_address != NULL) 69 | twopt->socket_address = my_strdup(socket_address); 70 | } 71 | 72 | void 73 | fstrm_tcp_writer_options_set_socket_port( 74 | struct fstrm_tcp_writer_options *twopt, 75 | const char *socket_port) 76 | { 77 | my_free(twopt->socket_port); 78 | if (socket_port != NULL) 79 | twopt->socket_port = my_strdup(socket_port); 80 | } 81 | 82 | static fstrm_res 83 | fstrm__tcp_writer_op_open(void *obj) 84 | { 85 | struct fstrm__tcp_writer *w = obj; 86 | 87 | /* Nothing to do if the socket is already connected. */ 88 | if (w->connected) 89 | return fstrm_res_success; 90 | 91 | /* Open an Internet socket. Request socket close-on-exec if available. */ 92 | #if defined(SOCK_CLOEXEC) 93 | w->fd = socket(w->ss.ss_family, SOCK_STREAM | SOCK_CLOEXEC, 0); 94 | if (w->fd < 0 && errno == EINVAL) 95 | w->fd = socket(w->ss.ss_family, SOCK_STREAM, 0); 96 | #else 97 | w->fd = socket(w->ss.ss_family, SOCK_STREAM, 0); 98 | #endif 99 | if (w->fd < 0) 100 | return fstrm_res_failure; 101 | 102 | /* 103 | * Request close-on-exec if available. There is nothing that can be done 104 | * if the F_SETFD call to fcntl() fails, so don't bother checking the 105 | * return value. 106 | * 107 | * https://lwn.net/Articles/412131/ 108 | * [ Ghosts of Unix past, part 2: Conflated designs ] 109 | */ 110 | #if defined(FD_CLOEXEC) 111 | int flags = fcntl(w->fd, F_GETFD, 0); 112 | if (flags != -1) { 113 | flags |= FD_CLOEXEC; 114 | (void) fcntl(w->fd, F_SETFD, flags); 115 | } 116 | #endif 117 | 118 | #if defined(SO_NOSIGPIPE) 119 | /* 120 | * Ugh, no signals, please! 121 | * 122 | * https://lwn.net/Articles/414618/ 123 | * [ Ghosts of Unix past, part 3: Unfixable designs ] 124 | */ 125 | static const int on = 1; 126 | if (setsockopt(w->fd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on)) != 0) { 127 | close(w->fd); 128 | return fstrm_res_failure; 129 | } 130 | #endif 131 | 132 | /* Connect the TCP socket. */ 133 | if (connect(w->fd, (struct sockaddr *) &w->ss, w->ss_len) < 0) { 134 | close(w->fd); 135 | return fstrm_res_failure; 136 | } 137 | 138 | w->connected = true; 139 | return fstrm_res_success; 140 | } 141 | 142 | static fstrm_res 143 | fstrm__tcp_writer_op_close(void *obj) 144 | { 145 | struct fstrm__tcp_writer *w = obj; 146 | if (w->connected) { 147 | w->connected = false; 148 | if (close(w->fd) != 0) 149 | return fstrm_res_failure; 150 | return fstrm_res_success; 151 | } 152 | return fstrm_res_failure; 153 | } 154 | 155 | static fstrm_res 156 | fstrm__tcp_writer_op_read(void *obj, void *buf, size_t nbytes) 157 | { 158 | struct fstrm__tcp_writer *w = obj; 159 | if (likely(w->connected)) { 160 | if (read_bytes(w->fd, buf, nbytes)) 161 | return fstrm_res_success; 162 | } 163 | return fstrm_res_failure; 164 | } 165 | 166 | static fstrm_res 167 | fstrm__tcp_writer_op_write(void *obj, const struct iovec *iov, int iovcnt) 168 | { 169 | struct fstrm__tcp_writer *w = obj; 170 | 171 | size_t nbytes = 0; 172 | ssize_t written = 0; 173 | int cur = 0; 174 | struct msghdr msg = { 175 | .msg_iov = (struct iovec *) /* Grr! */ iov, 176 | .msg_iovlen = iovcnt, 177 | }; 178 | 179 | if (unlikely(!w->connected)) 180 | return fstrm_res_failure; 181 | 182 | for (int i = 0; i < iovcnt; i++) 183 | nbytes += iov[i].iov_len; 184 | 185 | for (;;) { 186 | do { 187 | written = sendmsg(w->fd, &msg, MSG_NOSIGNAL); 188 | } while (written == -1 && errno == EINTR); 189 | if (written == -1) 190 | return fstrm_res_failure; 191 | if (cur == 0 && written == (ssize_t) nbytes) 192 | return fstrm_res_success; 193 | 194 | while (written >= (ssize_t) msg.msg_iov[cur].iov_len) 195 | written -= msg.msg_iov[cur++].iov_len; 196 | 197 | if (cur == iovcnt) 198 | return fstrm_res_success; 199 | 200 | msg.msg_iov[cur].iov_base = (void *) 201 | ((char *) msg.msg_iov[cur].iov_base + written); 202 | msg.msg_iov[cur].iov_len -= written; 203 | } 204 | } 205 | 206 | static fstrm_res 207 | fstrm__tcp_writer_op_destroy(void *obj) 208 | { 209 | struct fstrm__tcp_writer *w = obj; 210 | my_free(w); 211 | return fstrm_res_success; 212 | } 213 | 214 | static fstrm_res 215 | fstrm__tcp_writer_fill_socket_port(struct fstrm__tcp_writer *w, 216 | const struct fstrm_tcp_writer_options *twopt) 217 | { 218 | uint64_t port = 0; 219 | char *endptr = NULL; 220 | 221 | port = strtoul(twopt->socket_port, &endptr, 0); 222 | if (*endptr != '\0' || port > UINT16_MAX) { 223 | return fstrm_res_failure; 224 | } 225 | 226 | if (w->ss.ss_family == AF_INET) { 227 | struct sockaddr_in *sai = (struct sockaddr_in *) &w->ss; 228 | sai->sin_port = htons(port); 229 | return fstrm_res_success; 230 | } else if (w->ss.ss_family == AF_INET6) { 231 | struct sockaddr_in6 *sai6 = (struct sockaddr_in6 *) &w->ss; 232 | sai6->sin6_port = htons(port); 233 | return fstrm_res_success; 234 | } 235 | 236 | return fstrm_res_failure; 237 | } 238 | 239 | static fstrm_res 240 | fstrm__tcp_writer_fill_socket_address(struct fstrm__tcp_writer *w, 241 | const struct fstrm_tcp_writer_options *twopt) 242 | { 243 | struct sockaddr_in *sai = (struct sockaddr_in *) &w->ss; 244 | struct sockaddr_in6 *sai6 = (struct sockaddr_in6 *) &w->ss; 245 | 246 | if (inet_pton(AF_INET, twopt->socket_address, &sai->sin_addr) == 1) { 247 | w->ss.ss_family = AF_INET; 248 | w->ss_len = sizeof(*sai); 249 | return fstrm_res_success; 250 | } else if (inet_pton(AF_INET6, twopt->socket_address, &sai6->sin6_addr) == 1) { 251 | w->ss.ss_family = AF_INET6; 252 | w->ss_len = sizeof(*sai6); 253 | return fstrm_res_success; 254 | } 255 | 256 | return fstrm_res_failure; 257 | } 258 | 259 | struct fstrm_writer * 260 | fstrm_tcp_writer_init(const struct fstrm_tcp_writer_options *twopt, 261 | const struct fstrm_writer_options *wopt) 262 | { 263 | struct fstrm_rdwr *rdwr; 264 | struct fstrm__tcp_writer *tw; 265 | 266 | if (twopt->socket_address == NULL || twopt->socket_port == NULL) 267 | return NULL; 268 | 269 | tw = my_calloc(1, sizeof(*tw)); 270 | 271 | if (!(fstrm__tcp_writer_fill_socket_address(tw, twopt) == fstrm_res_success && 272 | fstrm__tcp_writer_fill_socket_port(tw, twopt) == fstrm_res_success)) 273 | { 274 | my_free(tw); 275 | return NULL; 276 | } 277 | 278 | rdwr = fstrm_rdwr_init(tw); 279 | fstrm_rdwr_set_destroy(rdwr, fstrm__tcp_writer_op_destroy); 280 | fstrm_rdwr_set_open(rdwr, fstrm__tcp_writer_op_open); 281 | fstrm_rdwr_set_close(rdwr, fstrm__tcp_writer_op_close); 282 | fstrm_rdwr_set_read(rdwr, fstrm__tcp_writer_op_read); 283 | fstrm_rdwr_set_write(rdwr, fstrm__tcp_writer_op_write); 284 | return fstrm_writer_init(wopt, &rdwr); 285 | } 286 | -------------------------------------------------------------------------------- /fstrm/tcp_writer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, 2018 by Farsight Security, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #ifndef FSTRM_TCP_WRITER_H 26 | #define FSTRM_TCP_WRITER_H 27 | 28 | /** 29 | * \defgroup fstrm_tcp_writer fstrm_tcp_writer 30 | * 31 | * `fstrm_tcp_writer` is an interface for opening an \ref fstrm_writer object 32 | * that is backed by I/O on a TCP socket. 33 | * 34 | * @{ 35 | */ 36 | 37 | /** 38 | * Initialize an `fstrm_tcp_writer_options` object, which is needed to 39 | * configure the socket address and socket port to be opened by the writer. 40 | * 41 | * \return 42 | * `fstrm_tcp_writer_options` object. 43 | */ 44 | struct fstrm_tcp_writer_options * 45 | fstrm_tcp_writer_options_init(void); 46 | 47 | /** 48 | * Destroy an `fstrm_tcp_writer_options` object. 49 | * 50 | * \param twopt 51 | * Pointer to `fstrm_tcp_writer_options` object. 52 | */ 53 | void 54 | fstrm_tcp_writer_options_destroy( 55 | struct fstrm_tcp_writer_options **twopt); 56 | 57 | /** 58 | * Set the `socket_address` option. This is the IPv4 or IPv6 address in 59 | * presentation format to be connected by the TCP socket. 60 | * 61 | * \param twopt 62 | * `fstrm_tcp_writer_options` object. 63 | * \param socket_address 64 | * The socket address. 65 | */ 66 | void 67 | fstrm_tcp_writer_options_set_socket_address( 68 | struct fstrm_tcp_writer_options *twopt, 69 | const char *socket_address); 70 | 71 | /** 72 | * Set the `socket_port` option. This is the TCP port number to be connected by 73 | * the TCP socket. 74 | * 75 | * \param twopt 76 | * `fstrm_tcp_writer_options` object. 77 | * \param socket_port 78 | * The TCP socket port number provided as a character string. 79 | * (When converted, the maximum allowed unsigned integer is 65535.) 80 | */ 81 | void 82 | fstrm_tcp_writer_options_set_socket_port( 83 | struct fstrm_tcp_writer_options *twopt, 84 | const char *socket_port); 85 | 86 | /** 87 | * Initialize the `fstrm_writer` object. Note that the TCP socket will not 88 | * actually be opened until a subsequent call to fstrm_writer_open(). 89 | * 90 | * \param twopt 91 | * `fstrm_tcp_writer_options` object. Must be non-NULL, and have the 92 | * `socket_address` and `socket_port` options set. 93 | * \param wopt 94 | * `fstrm_writer_options` object. May be NULL, in which chase default 95 | * values will be used. 96 | * 97 | * \return 98 | * `fstrm_writer` object. 99 | * \retval 100 | * NULL on failure. 101 | */ 102 | struct fstrm_writer * 103 | fstrm_tcp_writer_init( 104 | const struct fstrm_tcp_writer_options *twopt, 105 | const struct fstrm_writer_options *wopt); 106 | 107 | /**@}*/ 108 | 109 | #endif /* FSTRM_TCP_WRITER_H */ 110 | -------------------------------------------------------------------------------- /fstrm/time.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014, 2016-2017 by Farsight Security, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #include "fstrm-private.h" 26 | 27 | #if HAVE_CLOCK_GETTIME 28 | 29 | #if HAVE_PTHREAD_CONDATTR_SETCLOCK 30 | bool 31 | fstrm__get_best_monotonic_clock_pthread(clockid_t *c) 32 | { 33 | bool res = false; 34 | int rc; 35 | struct timespec ts; 36 | pthread_condattr_t ca; 37 | 38 | rc = pthread_condattr_init(&ca); 39 | assert(rc == 0); 40 | 41 | #if defined(CLOCK_MONOTONIC_COARSE) 42 | *c = CLOCK_MONOTONIC_COARSE; 43 | if (clock_gettime(*c, &ts) == 0 && 44 | pthread_condattr_setclock(&ca, *c) == 0) 45 | { 46 | res = true; 47 | goto out; 48 | } 49 | #endif 50 | 51 | #if defined(CLOCK_MONOTONIC_RAW) 52 | *c = CLOCK_MONOTONIC_RAW; 53 | if (clock_gettime(*c, &ts) == 0 && 54 | pthread_condattr_setclock(&ca, *c) == 0) 55 | { 56 | res = true; 57 | goto out; 58 | } 59 | #endif 60 | 61 | #if defined(CLOCK_MONOTONIC_FAST) 62 | *c = CLOCK_MONOTONIC_FAST; 63 | if (clock_gettime(*c, &ts) == 0 && 64 | pthread_condattr_setclock(&ca, *c) == 0) 65 | { 66 | res = true; 67 | goto out; 68 | } 69 | #endif 70 | 71 | #if defined(CLOCK_MONOTONIC) 72 | *c = CLOCK_MONOTONIC; 73 | if (clock_gettime(*c, &ts) == 0 && 74 | pthread_condattr_setclock(&ca, *c) == 0) 75 | { 76 | res = true; 77 | goto out; 78 | } 79 | #endif 80 | 81 | out: 82 | rc = pthread_condattr_destroy(&ca); 83 | assert(rc == 0); 84 | return res; 85 | } 86 | #endif /* HAVE_PTHREAD_CONDATTR_SETCLOCK */ 87 | 88 | bool 89 | fstrm__get_best_monotonic_clock_gettime(clockid_t *c) 90 | { 91 | struct timespec ts; 92 | 93 | #if defined(CLOCK_MONOTONIC_COARSE) 94 | if (!clock_gettime((*c) = CLOCK_MONOTONIC_COARSE, &ts)) 95 | return true; 96 | #endif 97 | 98 | #if defined(CLOCK_MONOTONIC_RAW) 99 | if (!clock_gettime((*c) = CLOCK_MONOTONIC_RAW, &ts)) 100 | return true; 101 | #endif 102 | 103 | #if defined(CLOCK_MONOTONIC_FAST) 104 | if (!clock_gettime((*c) = CLOCK_MONOTONIC_FAST, &ts)) 105 | return true; 106 | #endif 107 | 108 | #if defined(CLOCK_MONOTONIC) 109 | if (!clock_gettime((*c) = CLOCK_MONOTONIC, &ts)) 110 | return true; 111 | #endif 112 | 113 | return false; 114 | } 115 | 116 | bool 117 | fstrm__get_best_monotonic_clocks(clockid_t *clkid_gettime, 118 | clockid_t *clkid_pthread, 119 | char **err) 120 | { 121 | if (clkid_gettime != NULL && 122 | !fstrm__get_best_monotonic_clock_gettime(clkid_gettime)) 123 | { 124 | if (err != NULL) 125 | *err = my_strdup("no clock available for clock_gettime()"); 126 | return false; 127 | } 128 | 129 | #if HAVE_PTHREAD_CONDATTR_SETCLOCK 130 | if (clkid_pthread != NULL && 131 | !fstrm__get_best_monotonic_clock_pthread(clkid_pthread)) 132 | { 133 | if (err != NULL) 134 | *err = my_strdup("no clock available for pthread_cond_timedwait()"); 135 | return false; 136 | } 137 | #endif 138 | 139 | return true; 140 | } 141 | 142 | #endif /* HAVE_CLOCK_GETTIME */ 143 | -------------------------------------------------------------------------------- /fstrm/unix_writer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 by Farsight Security, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "fstrm-private.h" 32 | 33 | struct fstrm_unix_writer_options { 34 | char *socket_path; 35 | }; 36 | 37 | struct fstrm__unix_writer { 38 | bool connected; 39 | int fd; 40 | struct sockaddr_un sa; 41 | }; 42 | 43 | struct fstrm_unix_writer_options * 44 | fstrm_unix_writer_options_init(void) 45 | { 46 | return my_calloc(1, sizeof(struct fstrm_unix_writer_options)); 47 | } 48 | 49 | void 50 | fstrm_unix_writer_options_destroy(struct fstrm_unix_writer_options **uwopt) 51 | { 52 | if (*uwopt != NULL) { 53 | my_free((*uwopt)->socket_path); 54 | my_free(*uwopt); 55 | } 56 | } 57 | 58 | void 59 | fstrm_unix_writer_options_set_socket_path( 60 | struct fstrm_unix_writer_options *uwopt, 61 | const char *socket_path) 62 | { 63 | my_free(uwopt->socket_path); 64 | if (socket_path != NULL) 65 | uwopt->socket_path = my_strdup(socket_path); 66 | } 67 | 68 | static fstrm_res 69 | fstrm__unix_writer_op_open(void *obj) 70 | { 71 | struct fstrm__unix_writer *w = obj; 72 | 73 | /* Nothing to do if the socket is already connected. */ 74 | if (w->connected) 75 | return fstrm_res_success; 76 | 77 | /* Open an AF_UNIX socket. Request socket close-on-exec if available. */ 78 | #if defined(SOCK_CLOEXEC) 79 | w->fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); 80 | if (w->fd < 0 && errno == EINVAL) 81 | w->fd = socket(AF_UNIX, SOCK_STREAM, 0); 82 | #else 83 | w->fd = socket(AF_UNIX, SOCK_STREAM, 0); 84 | #endif 85 | if (w->fd < 0) 86 | return fstrm_res_failure; 87 | 88 | /* 89 | * Request close-on-exec if available. There is nothing that can be done 90 | * if the F_SETFD call to fcntl() fails, so don't bother checking the 91 | * return value. 92 | * 93 | * https://lwn.net/Articles/412131/ 94 | * [ Ghosts of Unix past, part 2: Conflated designs ] 95 | */ 96 | #if defined(FD_CLOEXEC) 97 | int flags = fcntl(w->fd, F_GETFD, 0); 98 | if (flags != -1) { 99 | flags |= FD_CLOEXEC; 100 | (void) fcntl(w->fd, F_SETFD, flags); 101 | } 102 | #endif 103 | 104 | #if defined(SO_NOSIGPIPE) 105 | /* 106 | * Ugh, no signals, please! 107 | * 108 | * https://lwn.net/Articles/414618/ 109 | * [ Ghosts of Unix past, part 3: Unfixable designs ] 110 | */ 111 | static const int on = 1; 112 | if (setsockopt(w->fd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on)) != 0) { 113 | close(w->fd); 114 | return fstrm_res_failure; 115 | } 116 | #endif 117 | 118 | /* Connect the AF_UNIX socket. */ 119 | if (connect(w->fd, (struct sockaddr *) &w->sa, sizeof(w->sa)) < 0) { 120 | close(w->fd); 121 | return fstrm_res_failure; 122 | } 123 | 124 | w->connected = true; 125 | return fstrm_res_success; 126 | } 127 | 128 | static fstrm_res 129 | fstrm__unix_writer_op_close(void *obj) 130 | { 131 | struct fstrm__unix_writer *w = obj; 132 | if (w->connected) { 133 | w->connected = false; 134 | if (close(w->fd) != 0) 135 | return fstrm_res_failure; 136 | return fstrm_res_success; 137 | } 138 | return fstrm_res_failure; 139 | } 140 | 141 | static fstrm_res 142 | fstrm__unix_writer_op_read(void *obj, void *buf, size_t nbytes) 143 | { 144 | struct fstrm__unix_writer *w = obj; 145 | if (likely(w->connected)) { 146 | if (read_bytes(w->fd, buf, nbytes)) 147 | return fstrm_res_success; 148 | } 149 | return fstrm_res_failure; 150 | } 151 | 152 | static fstrm_res 153 | fstrm__unix_writer_op_write(void *obj, const struct iovec *iov, int iovcnt) 154 | { 155 | struct fstrm__unix_writer *w = obj; 156 | 157 | size_t nbytes = 0; 158 | ssize_t written = 0; 159 | int cur = 0; 160 | struct msghdr msg = { 161 | .msg_iov = (struct iovec *) /* Grr! */ iov, 162 | .msg_iovlen = iovcnt, 163 | }; 164 | 165 | if (unlikely(!w->connected)) 166 | return fstrm_res_failure; 167 | 168 | for (int i = 0; i < iovcnt; i++) 169 | nbytes += iov[i].iov_len; 170 | 171 | for (;;) { 172 | do { 173 | written = sendmsg(w->fd, &msg, MSG_NOSIGNAL); 174 | } while (written == -1 && errno == EINTR); 175 | if (written == -1) 176 | return fstrm_res_failure; 177 | if (cur == 0 && written == (ssize_t) nbytes) 178 | return fstrm_res_success; 179 | 180 | while (written >= (ssize_t) msg.msg_iov[cur].iov_len) 181 | written -= msg.msg_iov[cur++].iov_len; 182 | 183 | if (cur == iovcnt) 184 | return fstrm_res_success; 185 | 186 | msg.msg_iov[cur].iov_base = (void *) 187 | ((char *) msg.msg_iov[cur].iov_base + written); 188 | msg.msg_iov[cur].iov_len -= written; 189 | } 190 | } 191 | 192 | static fstrm_res 193 | fstrm__unix_writer_op_destroy(void *obj) 194 | { 195 | struct fstrm__unix_writer *w = obj; 196 | my_free(w); 197 | return fstrm_res_success; 198 | } 199 | 200 | struct fstrm_writer * 201 | fstrm_unix_writer_init(const struct fstrm_unix_writer_options *uwopt, 202 | const struct fstrm_writer_options *wopt) 203 | { 204 | struct fstrm_rdwr *rdwr; 205 | struct fstrm__unix_writer *uw; 206 | 207 | if (uwopt->socket_path == NULL) 208 | return NULL; 209 | 210 | if (strlen(uwopt->socket_path) + 1 > sizeof(uw->sa.sun_path)) 211 | return NULL; 212 | 213 | uw = my_calloc(1, sizeof(*uw)); 214 | uw->sa.sun_family = AF_UNIX; 215 | strncpy(uw->sa.sun_path, uwopt->socket_path, sizeof(uw->sa.sun_path) - 1); 216 | 217 | rdwr = fstrm_rdwr_init(uw); 218 | fstrm_rdwr_set_destroy(rdwr, fstrm__unix_writer_op_destroy); 219 | fstrm_rdwr_set_open(rdwr, fstrm__unix_writer_op_open); 220 | fstrm_rdwr_set_close(rdwr, fstrm__unix_writer_op_close); 221 | fstrm_rdwr_set_read(rdwr, fstrm__unix_writer_op_read); 222 | fstrm_rdwr_set_write(rdwr, fstrm__unix_writer_op_write); 223 | return fstrm_writer_init(wopt, &rdwr); 224 | } 225 | -------------------------------------------------------------------------------- /fstrm/unix_writer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 by Farsight Security, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #ifndef FSTRM_UNIX_WRITER_H 26 | #define FSTRM_UNIX_WRITER_H 27 | 28 | /** 29 | * \defgroup fstrm_unix_writer fstrm_unix_writer 30 | * 31 | * `fstrm_unix_writer` is an interface for opening an \ref fstrm_writer object 32 | * that is backed by I/O on a stream-oriented (`SOCK_STREAM`) Unix socket. 33 | * 34 | * @{ 35 | */ 36 | 37 | /** 38 | * Initialize an `fstrm_unix_writer_options` object, which is needed to 39 | * configure the socket path to be opened by the writer. 40 | * 41 | * \return 42 | * `fstrm_unix_writer_options` object. 43 | */ 44 | struct fstrm_unix_writer_options * 45 | fstrm_unix_writer_options_init(void); 46 | 47 | /** 48 | * Destroy an `fstrm_unix_writer_options` object. 49 | * 50 | * \param uwopt 51 | * Pointer to `fstrm_unix_writer_options` object. 52 | */ 53 | void 54 | fstrm_unix_writer_options_destroy( 55 | struct fstrm_unix_writer_options **uwopt); 56 | 57 | /** 58 | * Set the `socket_path` option. This is a filesystem path that will be 59 | * connected to as an `AF_UNIX` socket. 60 | * 61 | * \param uwopt 62 | * `fstrm_unix_writer_options` object. 63 | * \param socket_path 64 | * The filesystem path to the `AF_UNIX` socket. 65 | */ 66 | void 67 | fstrm_unix_writer_options_set_socket_path( 68 | struct fstrm_unix_writer_options *uwopt, 69 | const char *socket_path); 70 | 71 | /** 72 | * Initialize the `fstrm_writer` object. Note that the `AF_UNIX` socket will not 73 | * actually be opened until a subsequent call to fstrm_writer_open(). 74 | * 75 | * \param uwopt 76 | * `fstrm_unix_writer_options` object. Must be non-NULL, and have the 77 | * `socket_path` option set. 78 | * \param wopt 79 | * `fstrm_writer_options` object. May be NULL, in which chase default 80 | * values will be used. 81 | * 82 | * \return 83 | * `fstrm_writer` object. 84 | * \retval 85 | * NULL on failure. 86 | */ 87 | struct fstrm_writer * 88 | fstrm_unix_writer_init( 89 | const struct fstrm_unix_writer_options *uwopt, 90 | const struct fstrm_writer_options *wopt); 91 | 92 | /**@}*/ 93 | 94 | #endif /* FSTRM_UNIX_WRITER_H */ 95 | -------------------------------------------------------------------------------- /libmy/.gitignore: -------------------------------------------------------------------------------- 1 | *.lo 2 | *.o 3 | .*swp 4 | .deps/ 5 | .dirstamp 6 | .libs/ 7 | -------------------------------------------------------------------------------- /libmy/COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2014 by Farsight Security, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /libmy/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2014 by Farsight Security, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /libmy/argv_loc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Local defines for the argv module 3 | * 4 | * Copyright 2000 by Gray Watson 5 | * 6 | * This file is part of the argv library. 7 | * 8 | * Permission to use, copy, modify, and distribute this software for 9 | * any purpose and without fee is hereby granted, provided that the 10 | * above copyright notice and this permission notice appear in all 11 | * copies, and that the name of Gray Watson not be used in advertising 12 | * or publicity pertaining to distribution of the document or software 13 | * without specific, written prior permission. 14 | * 15 | * Gray Watson makes no representations about the suitability of the 16 | * software described herein for any purpose. It is provided "as is" 17 | * without express or implied warranty. 18 | * 19 | * The author may be contacted via http://256.com/gray/ 20 | * 21 | * $Id: argv_loc.h,v 1.50 2007/01/08 20:32:57 gray Exp $ 22 | */ 23 | 24 | #ifndef __ARGV_LOC_H__ 25 | #define __ARGV_LOC_H__ 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #if 0 30 | } 31 | #endif 32 | #endif 33 | 34 | #include "argv.h" /* to get the types */ 35 | 36 | /* 37 | * some compilation options 38 | */ 39 | 40 | /* to include RCS ids in the code */ 41 | #ifndef INCLUDE_RCS_IDS 42 | #define INCLUDE_RCS_IDS 1 43 | #endif 44 | 45 | /* 46 | * generic constants 47 | */ 48 | /* special consideration for NULL. some compilers bitch if I redefine it */ 49 | #ifndef NULL 50 | #define NULL 0L 51 | #endif 52 | 53 | #undef MIN 54 | #define MIN(a,b) ((a) < (b) ? (a) : (b)) 55 | 56 | #undef NOERROR 57 | #define NOERROR 0 58 | 59 | #undef ERROR 60 | #define ERROR (-1) 61 | 62 | #undef STDIN 63 | #define STDIN 0 64 | 65 | /* 66 | * local argv defines 67 | */ 68 | 69 | #define ERROR_STREAM_INIT (FILE *)0x1 /* hack to init stderr FILE* */ 70 | #define NO_VALUE (-1) /* no mandatory args value */ 71 | #define ARRAY_INCR 10 /* increment by 10 every 10 */ 72 | #define SCREEN_WIDTH 79 /* width of screen till wrap */ 73 | #define BITS_IN_BYTE 8 /* bits in a byte */ 74 | #define SPECIAL_CHARS "e\033^^\"\"''\\\\n\nr\rt\tb\bf\fa\007" 75 | #define DUMP_SPACE_BUF 128 /* space for memory dump */ 76 | #define ARG_MALLOC_INCR 20 /* alloc in 10 increments */ 77 | #define FILE_LINE_SIZE 1024 /* max size of file lines */ 78 | 79 | /* internal flags set in the ar_type field */ 80 | /* NOTE: other external flags defined in argv.h */ 81 | #define ARGV_FLAG_USED (1 << 12) /* if arg has been specified */ 82 | 83 | /* error messages */ 84 | #define USAGE_ERROR_NAME "usage problem" 85 | #define INTERNAL_ERROR_NAME "internal argv error" 86 | 87 | /* 88 | * settings to vary the output of the argument routines 89 | */ 90 | 91 | #define PROGRAM_NAME 256 /* max size of program name */ 92 | #define EXIT_CODE 1 /* argv exit code for errors */ 93 | 94 | /* global env settings */ 95 | #define GLOBAL_NAME "GLOBAL_ARGV" /* global argv env name */ 96 | #define GLOBAL_CLOSE "close=" /* close arg setting */ 97 | #define GLOBAL_ENV "env=" /* env setting */ 98 | #define GLOBAL_ERROR "error=" /* error setting */ 99 | #define GLOBAL_MULTI "multi=" /* multi setting */ 100 | #define GLOBAL_USAGE "usage=" /* usage setting */ 101 | #define GLOBAL_LASTTOG "lasttog=" /* last-arg toggle */ 102 | 103 | /* special argument definitions */ 104 | #define LAST_ARG "--" /* arg to mark end of args */ 105 | #define LONG_PREFIX "--" /* prefix for long args */ 106 | #define SHORT_PREFIX "-" /* prefix for short args */ 107 | #define UNKNOWN_ARG "??" /* unknown argument output */ 108 | #define ARG_EQUALS '=' /* to assign value to option */ 109 | #define NUMBER_ARG_CHARS "0123456789+-." /* characters in numbers */ 110 | 111 | /* how to produce the env var using sprintf and the argv_program variable */ 112 | #define ENVIRON_FORMAT "ARGV_%s" 113 | 114 | /* special short-argument strings */ 115 | #define USAGE_CHAR_ARG '?' /* default short-opt usage */ 116 | 117 | /* special long-argument strings */ 118 | #define DISPLAY_ARG "argv-display" /* display arg variable vals */ 119 | #define FILE_ARG "argv-file" /* read args from file */ 120 | #define HELP_ARG "help" /* default help option */ 121 | #define USAGE_ARG "usage" /* default usage option */ 122 | #define USAGE_SHORT_ARG "usage-short" /* default usage-short opt */ 123 | #define USAGE_LONG_ARG "usage-long" /* default usage-long opt */ 124 | #define USAGE_ALL_ARG "usage-all" /* default usage-all opt */ 125 | #define VERSION_ARG "version" /* default version option */ 126 | 127 | /* spacing on line for usage messages */ 128 | #define SHORT_COLUMN 0 /* spaces to indent for short-args */ 129 | #define LONG_COLUMN 18 /* column for long options */ 130 | #define COMMENT_COLUMN 34 /* column for comments */ 131 | 132 | /* some in-line "labels" for comments */ 133 | #define USAGE_LABEL "Usage: " /* usage message start */ 134 | #define LONG_LABEL "or " /* put before long-option */ 135 | #define COMMENT_LABEL "" /* put before comments */ 136 | #define ARRAY_LABEL " array" /* put after displayed type */ 137 | #define BOOL_ARG_LABEL "yes|no" /* label for bool-arg arg */ 138 | 139 | /* some sizeof defines */ 140 | #define SHORT_PREFIX_LENGTH (sizeof(SHORT_PREFIX) - 1) 141 | #define LONG_PREFIX_LENGTH (sizeof(LONG_PREFIX) - 1) 142 | 143 | #define USAGE_LABEL_LENGTH (sizeof(USAGE_LABEL) - 1) 144 | #define COMMENT_LABEL_LENGTH (sizeof(COMMENT_LABEL) - 1) 145 | #define LONG_LABEL_LENGTH (sizeof(LONG_LABEL) - 1) 146 | #define UNKNOWN_ARG_LENGTH (sizeof(UNKNOWN_ARG) - 1) 147 | #define BOOL_ARG_LENGTH (sizeof(BOOL_ARG_LABEL) - 1) 148 | 149 | #define HAS_ARG(type) (! (ARGV_TYPE(type) == ARGV_BOOL \ 150 | || ARGV_TYPE(type) == ARGV_BOOL_NEG \ 151 | || ARGV_TYPE(type) == ARGV_INCR \ 152 | || ARGV_TYPE(type) == ARGV_BOOL_INT \ 153 | || ARGV_TYPE(type) == ARGV_BOOL_INT_NEG)) 154 | 155 | /******************************** argv types *********************************/ 156 | 157 | /* strcture defining argv types */ 158 | typedef struct { 159 | unsigned int at_value; /* value of the type */ 160 | const char *at_name; /* name of the type */ 161 | unsigned int at_size; /* size of type */ 162 | const char *at_desc; /* description of the type */ 163 | } argv_type_t; 164 | 165 | static argv_type_t argv_types[] = { 166 | { ARGV_BOOL, "flag", sizeof(char), 167 | "if option used, set variable to 1" }, 168 | { ARGV_BOOL_NEG, "negative flag", sizeof(int), 169 | "if option used, set variable to 0" }, 170 | { ARGV_BOOL_ARG, "flag with arg", sizeof(char), 171 | "like boolean but with an argument, true/yes/1 sets var to 1" }, 172 | { ARGV_CHAR, "character", sizeof(char), 173 | "single character" }, 174 | { ARGV_CHAR_P, "string", sizeof(char *), 175 | "multiple characters terminated with a '\\0'" }, 176 | { ARGV_SHORT, "short integer", sizeof(short), 177 | "decimal short-sized integer value" }, 178 | { ARGV_U_SHORT, "unsigned short integer", sizeof(unsigned short), 179 | "decimal unsigned short-sized integer value" }, 180 | { ARGV_INT, "integer", sizeof(int), 181 | "decimal integer value" }, 182 | { ARGV_U_INT, "unsigned integer", sizeof(unsigned int), 183 | "decimal unsigned integer value" }, 184 | { ARGV_LONG, "long integer", sizeof(long), 185 | "decimal long-sized integer value" }, 186 | { ARGV_U_LONG, "unsigned long", sizeof(unsigned long), 187 | "decimal unsigned long-sized integer value" }, 188 | { ARGV_FLOAT, "floating point", sizeof(float), 189 | "real number with decimal point" }, 190 | { ARGV_DOUBLE, "double floating point", sizeof(double), 191 | "double precision real number with decimal point" }, 192 | { ARGV_BIN, "binary", sizeof(int), 193 | "base 2 value with digits of 0 or 1" }, 194 | { ARGV_OCT, "octal", sizeof(int), 195 | "base 8 value with digits from 0-7" }, 196 | { ARGV_HEX, "hexadecimal", sizeof(int), 197 | "base 16 value with digits from 0-9, A-F" }, 198 | { ARGV_INCR, "increment", sizeof(int), 199 | "increment variable each time option used" }, 200 | { ARGV_SIZE, "long size", sizeof(long), 201 | "size as long int + [bkmg] b=byte,k=kilo,m=meg,g=gig" }, 202 | { ARGV_U_SIZE, "unsigned long size", sizeof(unsigned long), 203 | "size as unsigned long int + [bkmg] b=byte,k=kilo,m=meg,g=gig" }, 204 | { ARGV_BOOL_INT, "integer boolean", sizeof(int), 205 | "if option used, set integer variable to 1" }, 206 | { ARGV_BOOL_INT_NEG, "integer boolean", sizeof(int), 207 | "if option used, set integer variable to 0" }, 208 | { ARGV_BOOL_INT_ARG, "integer boolean", sizeof(int), 209 | "like boolean but with an argument, true/yes/1 sets integer var to 1" }, 210 | { 0, NULL, 0, NULL } 211 | }; 212 | 213 | #ifdef __cplusplus 214 | #if 0 215 | { 216 | #endif 217 | } 218 | #endif 219 | 220 | #endif /* ! __ARGV_LOC_H__ */ 221 | -------------------------------------------------------------------------------- /libmy/m4/ax_compare_version.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_compare_version.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # This macro compares two version strings. Due to the various number of 12 | # minor-version numbers that can exist, and the fact that string 13 | # comparisons are not compatible with numeric comparisons, this is not 14 | # necessarily trivial to do in a autoconf script. This macro makes doing 15 | # these comparisons easy. 16 | # 17 | # The six basic comparisons are available, as well as checking equality 18 | # limited to a certain number of minor-version levels. 19 | # 20 | # The operator OP determines what type of comparison to do, and can be one 21 | # of: 22 | # 23 | # eq - equal (test A == B) 24 | # ne - not equal (test A != B) 25 | # le - less than or equal (test A <= B) 26 | # ge - greater than or equal (test A >= B) 27 | # lt - less than (test A < B) 28 | # gt - greater than (test A > B) 29 | # 30 | # Additionally, the eq and ne operator can have a number after it to limit 31 | # the test to that number of minor versions. 32 | # 33 | # eq0 - equal up to the length of the shorter version 34 | # ne0 - not equal up to the length of the shorter version 35 | # eqN - equal up to N sub-version levels 36 | # neN - not equal up to N sub-version levels 37 | # 38 | # When the condition is true, shell commands ACTION-IF-TRUE are run, 39 | # otherwise shell commands ACTION-IF-FALSE are run. The environment 40 | # variable 'ax_compare_version' is always set to either 'true' or 'false' 41 | # as well. 42 | # 43 | # Examples: 44 | # 45 | # AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8]) 46 | # AX_COMPARE_VERSION([3.15],[lt],[3.15.8]) 47 | # 48 | # would both be true. 49 | # 50 | # AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8]) 51 | # AX_COMPARE_VERSION([3.15],[gt],[3.15.8]) 52 | # 53 | # would both be false. 54 | # 55 | # AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8]) 56 | # 57 | # would be true because it is only comparing two minor versions. 58 | # 59 | # AX_COMPARE_VERSION([3.15.7],[eq0],[3.15]) 60 | # 61 | # would be true because it is only comparing the lesser number of minor 62 | # versions of the two values. 63 | # 64 | # Note: The characters that separate the version numbers do not matter. An 65 | # empty string is the same as version 0. OP is evaluated by autoconf, not 66 | # configure, so must be a string, not a variable. 67 | # 68 | # The author would like to acknowledge Guido Draheim whose advice about 69 | # the m4_case and m4_ifvaln functions make this macro only include the 70 | # portions necessary to perform the specific comparison specified by the 71 | # OP argument in the final configure script. 72 | # 73 | # LICENSE 74 | # 75 | # Copyright (c) 2008 Tim Toolan 76 | # 77 | # Copying and distribution of this file, with or without modification, are 78 | # permitted in any medium without royalty provided the copyright notice 79 | # and this notice are preserved. This file is offered as-is, without any 80 | # warranty. 81 | 82 | #serial 11 83 | 84 | dnl ######################################################################### 85 | AC_DEFUN([AX_COMPARE_VERSION], [ 86 | AC_REQUIRE([AC_PROG_AWK]) 87 | 88 | # Used to indicate true or false condition 89 | ax_compare_version=false 90 | 91 | # Convert the two version strings to be compared into a format that 92 | # allows a simple string comparison. The end result is that a version 93 | # string of the form 1.12.5-r617 will be converted to the form 94 | # 0001001200050617. In other words, each number is zero padded to four 95 | # digits, and non digits are removed. 96 | AS_VAR_PUSHDEF([A],[ax_compare_version_A]) 97 | A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ 98 | -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ 99 | -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ 100 | -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ 101 | -e 's/[[^0-9]]//g'` 102 | 103 | AS_VAR_PUSHDEF([B],[ax_compare_version_B]) 104 | B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ 105 | -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ 106 | -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ 107 | -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ 108 | -e 's/[[^0-9]]//g'` 109 | 110 | dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary 111 | dnl # then the first line is used to determine if the condition is true. 112 | dnl # The sed right after the echo is to remove any indented white space. 113 | m4_case(m4_tolower($2), 114 | [lt],[ 115 | ax_compare_version=`echo "x$A 116 | x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"` 117 | ], 118 | [gt],[ 119 | ax_compare_version=`echo "x$A 120 | x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"` 121 | ], 122 | [le],[ 123 | ax_compare_version=`echo "x$A 124 | x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"` 125 | ], 126 | [ge],[ 127 | ax_compare_version=`echo "x$A 128 | x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"` 129 | ],[ 130 | dnl Split the operator from the subversion count if present. 131 | m4_bmatch(m4_substr($2,2), 132 | [0],[ 133 | # A count of zero means use the length of the shorter version. 134 | # Determine the number of characters in A and B. 135 | ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'` 136 | ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'` 137 | 138 | # Set A to no more than B's length and B to no more than A's length. 139 | A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"` 140 | B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"` 141 | ], 142 | [[0-9]+],[ 143 | # A count greater than zero means use only that many subversions 144 | A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` 145 | B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` 146 | ], 147 | [.+],[ 148 | AC_WARNING( 149 | [illegal OP numeric parameter: $2]) 150 | ],[]) 151 | 152 | # Pad zeros at end of numbers to make same length. 153 | ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`" 154 | B="$B`echo $A | sed 's/./0/g'`" 155 | A="$ax_compare_version_tmp_A" 156 | 157 | # Check for equality or inequality as necessary. 158 | m4_case(m4_tolower(m4_substr($2,0,2)), 159 | [eq],[ 160 | test "x$A" = "x$B" && ax_compare_version=true 161 | ], 162 | [ne],[ 163 | test "x$A" != "x$B" && ax_compare_version=true 164 | ],[ 165 | AC_WARNING([illegal OP parameter: $2]) 166 | ]) 167 | ]) 168 | 169 | AS_VAR_POPDEF([A])dnl 170 | AS_VAR_POPDEF([B])dnl 171 | 172 | dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE. 173 | if test "$ax_compare_version" = "true" ; then 174 | m4_ifvaln([$4],[$4],[:])dnl 175 | m4_ifvaln([$5],[else $5])dnl 176 | fi 177 | ]) dnl AX_COMPARE_VERSION 178 | -------------------------------------------------------------------------------- /libmy/m4/ax_define_dir.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_define_dir.html 3 | # =========================================================================== 4 | # 5 | # OBSOLETE MACRO 6 | # 7 | # Deprecated because it does not comply with the GNU Coding Standards. See 8 | # the autoconf manual section "Defining Directories" for alternatives. 9 | # 10 | # SYNOPSIS 11 | # 12 | # AX_DEFINE_DIR(VARNAME, DIR [, DESCRIPTION]) 13 | # 14 | # DESCRIPTION 15 | # 16 | # This macro sets VARNAME to the expansion of the DIR variable, taking 17 | # care of fixing up ${prefix} and such. 18 | # 19 | # VARNAME is then offered as both an output variable and a C preprocessor 20 | # symbol. 21 | # 22 | # Example: 23 | # 24 | # AX_DEFINE_DIR([DATADIR], [datadir], [Where data are placed to.]) 25 | # 26 | # LICENSE 27 | # 28 | # Copyright (c) 2008 Stepan Kasal 29 | # Copyright (c) 2008 Andreas Schwab 30 | # Copyright (c) 2008 Guido U. Draheim 31 | # Copyright (c) 2008 Alexandre Oliva 32 | # 33 | # Copying and distribution of this file, with or without modification, are 34 | # permitted in any medium without royalty provided the copyright notice 35 | # and this notice are preserved. This file is offered as-is, without any 36 | # warranty. 37 | 38 | #serial 8 39 | 40 | AU_ALIAS([AC_DEFINE_DIR], [AX_DEFINE_DIR]) 41 | AC_DEFUN([AX_DEFINE_DIR], [ 42 | prefix_NONE= 43 | exec_prefix_NONE= 44 | test "x$prefix" = xNONE && prefix_NONE=yes && prefix=$ac_default_prefix 45 | test "x$exec_prefix" = xNONE && exec_prefix_NONE=yes && exec_prefix=$prefix 46 | dnl In Autoconf 2.60, ${datadir} refers to ${datarootdir}, which in turn 47 | dnl refers to ${prefix}. Thus we have to use `eval' twice. 48 | eval ax_define_dir="\"[$]$2\"" 49 | eval ax_define_dir="\"$ax_define_dir\"" 50 | AC_SUBST($1, "$ax_define_dir") 51 | AC_DEFINE_UNQUOTED($1, "$ax_define_dir", [$3]) 52 | test "$prefix_NONE" && prefix=NONE 53 | test "$exec_prefix_NONE" && exec_prefix=NONE 54 | ]) 55 | -------------------------------------------------------------------------------- /libmy/m4/ax_prog_xsltproc.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_prog_xsltproc.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_PROG_XSLTPROC([default-flags]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Find an xsltproc executable. 12 | # 13 | # Input: 14 | # 15 | # "default-flags" is the default $XSLTPROC_FLAGS, which will be overridden 16 | # if the user specifies --with-xsltproc-flags. 17 | # 18 | # Output: 19 | # 20 | # $XSLTPROC contains the path to xsltproc, or is empty if none was found 21 | # or the user specified --without-xsltproc. $XSLTPROC_FLAGS contains the 22 | # flags to use with xsltproc. 23 | # 24 | # LICENSE 25 | # 26 | # Copyright (c) 2008,2009 Zmanda Inc. 27 | # Copyright (c) 2008,2009 Dustin J. Mitchell 28 | # 29 | # This program is free software; you can redistribute it and/or modify it 30 | # under the terms of the GNU General Public License as published by the 31 | # Free Software Foundation; either version 2 of the License, or (at your 32 | # option) any later version. 33 | # 34 | # This program is distributed in the hope that it will be useful, but 35 | # WITHOUT ANY WARRANTY; without even the implied warranty of 36 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 37 | # Public License for more details. 38 | # 39 | # You should have received a copy of the GNU General Public License along 40 | # with this program. If not, see . 41 | # 42 | # As a special exception, the respective Autoconf Macro's copyright owner 43 | # gives unlimited permission to copy, distribute and modify the configure 44 | # scripts that are the output of Autoconf when processing the Macro. You 45 | # need not follow the terms of the GNU General Public License when using 46 | # or distributing such scripts, even though portions of the text of the 47 | # Macro appear in them. The GNU General Public License (GPL) does govern 48 | # all other use of the material that constitutes the Autoconf Macro. 49 | # 50 | # This special exception to the GPL applies to versions of the Autoconf 51 | # Macro released by the Autoconf Archive. When you make and distribute a 52 | # modified version of the Autoconf Macro, you may extend this special 53 | # exception to the GPL to apply to your modified version as well. 54 | 55 | #serial 5 56 | 57 | AU_ALIAS([AC_PROG_XSLTPROC], [AX_PROG_XSLTPROC]) 58 | AC_DEFUN([AX_PROG_XSLTPROC], 59 | [ 60 | XSLTPROC_FLAGS="$1" 61 | AC_SUBST(XSLTPROC_FLAGS) 62 | 63 | # The (lack of) whitespace and overquoting here are all necessary for 64 | # proper formatting. 65 | AC_ARG_WITH(xsltproc, 66 | AS_HELP_STRING([--with-xsltproc[[[[[=PATH]]]]]], 67 | [Use the xsltproc binary in PATH.]), 68 | [ ac_with_xsltproc=$withval; ], 69 | [ ac_with_xsltproc=maybe; ]) 70 | 71 | AC_ARG_WITH(xsltproc-flags, 72 | AS_HELP_STRING([ --with-xsltproc-flags=FLAGS], 73 | [Flags to pass to xsltproc (default $1)]), 74 | [ if test "x$withval" == "xno"; then 75 | XSLTPROC_FLAGS='' 76 | else 77 | if test "x$withval" != "xyes"; then 78 | XSLTPROC_FLAGS="$withval" 79 | fi 80 | fi 81 | ]) 82 | 83 | # search for xsltproc if it wasn't specified 84 | if test "$ac_with_xsltproc" = "yes" -o "$ac_with_xsltproc" = "maybe"; then 85 | AC_PATH_PROGS(XSLTPROC,xsltproc) 86 | else 87 | if test "$ac_with_xsltproc" != "no"; then 88 | if test -x "$ac_with_xsltproc"; then 89 | XSLTPROC="$ac_with_xsltproc"; 90 | else 91 | AC_MSG_WARN([Specified xsltproc of $ac_with_xsltproc isn't]) 92 | AC_MSG_WARN([executable; searching for an alternative.]) 93 | AC_PATH_PROGS(XSLTPROC,xsltproc) 94 | fi 95 | fi 96 | fi 97 | ]) 98 | -------------------------------------------------------------------------------- /libmy/m4/ld-version-script.m4: -------------------------------------------------------------------------------- 1 | # ld-version-script.m4 serial 3 2 | dnl Copyright (C) 2008-2014 Free Software Foundation, Inc. 3 | dnl This file is free software; the Free Software Foundation 4 | dnl gives unlimited permission to copy and/or distribute it, 5 | dnl with or without modifications, as long as this notice is preserved. 6 | 7 | dnl From Simon Josefsson 8 | 9 | # FIXME: The test below returns a false positive for mingw 10 | # cross-compiles, 'local:' statements does not reduce number of 11 | # exported symbols in a DLL. Use --disable-ld-version-script to work 12 | # around the problem. 13 | 14 | # gl_LD_VERSION_SCRIPT 15 | # -------------------- 16 | # Check if LD supports linker scripts, and define automake conditional 17 | # HAVE_LD_VERSION_SCRIPT if so. 18 | AC_DEFUN([gl_LD_VERSION_SCRIPT], 19 | [ 20 | AC_ARG_ENABLE([ld-version-script], 21 | AS_HELP_STRING([--enable-ld-version-script], 22 | [enable linker version script (default is enabled when possible)]), 23 | [have_ld_version_script=$enableval], []) 24 | if test -z "$have_ld_version_script"; then 25 | AC_MSG_CHECKING([if LD -Wl,--version-script works]) 26 | save_LDFLAGS="$LDFLAGS" 27 | LDFLAGS="$LDFLAGS -Wl,--version-script=conftest.map" 28 | cat > conftest.map < conftest.map < 21 | # Copyright (c) 2008 Dustin J. Mitchell 22 | # 23 | # This program is free software; you can redistribute it and/or modify it 24 | # under the terms of the GNU General Public License as published by the 25 | # Free Software Foundation; either version 2 of the License, or (at your 26 | # option) any later version. 27 | # 28 | # This program is distributed in the hope that it will be useful, but 29 | # WITHOUT ANY WARRANTY; without even the implied warranty of 30 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 31 | # Public License for more details. 32 | # 33 | # You should have received a copy of the GNU General Public License along 34 | # with this program. If not, see . 35 | # 36 | # As a special exception, the respective Autoconf Macro's copyright owner 37 | # gives unlimited permission to copy, distribute and modify the configure 38 | # scripts that are the output of Autoconf when processing the Macro. You 39 | # need not follow the terms of the GNU General Public License when using 40 | # or distributing such scripts, even though portions of the text of the 41 | # Macro appear in them. The GNU General Public License (GPL) does govern 42 | # all other use of the material that constitutes the Autoconf Macro. 43 | # 44 | # This special exception to the GPL applies to versions of the Autoconf 45 | # Macro released by the Autoconf Archive. When you make and distribute a 46 | # modified version of the Autoconf Macro, you may extend this special 47 | # exception to the GPL to apply to your modified version as well. 48 | 49 | #serial 5 50 | 51 | AC_DEFUN([MY_CHECK_DOCBOOK_NS_XSLT_MIN], 52 | [ 53 | AC_REQUIRE([AX_PROG_XSLTPROC]) 54 | 55 | AC_CACHE_CHECK([for current DocBook-NS XSLT version], [ac_cv_docbook_ns_xslt_current_version], 56 | [ 57 | ac_cv_docbook_ns_xslt_current_version=no 58 | 59 | if test -n "$XSLTPROC"; then 60 | cat >conftest.xsl < 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | EOF 73 | echo "Trying '$XSLTPROC $XSLTPROC_FLAGS http://docbook.sourceforge.net/release/xsl-ns/current/VERSION' with input:" >&AS_MESSAGE_LOG_FD 74 | echo "====" >&AS_MESSAGE_LOG_FD 75 | cat conftest.xsl >&AS_MESSAGE_LOG_FD 76 | echo "====" >&AS_MESSAGE_LOG_FD 77 | 78 | ac_cv_docbook_ns_xslt_current_version=`$XSLTPROC $XSLTPROC_FLAGS conftest.xsl http://docbook.sourceforge.net/release/xsl-ns/current/VERSION 2>&AS_MESSAGE_LOG_FD` 79 | 80 | if test "$?" != 0; then 81 | ac_cv_docbook_ns_xslt_current_version='no' 82 | fi 83 | 84 | rm conftest.xsl 85 | fi 86 | ]) 87 | 88 | DOCBOOK_NS_XSLT_CURRENT_VERSION="$ac_cv_docbook_ns_xslt_current_version" 89 | AC_MSG_CHECKING([whether DocBook-NS XSLT version is $1 or newer]) 90 | 91 | if test x"$DOCBOOK_NS_XSLT_CURRENT_VERSION" = x"no"; then 92 | AC_MSG_RESULT([no]) 93 | else 94 | AX_COMPARE_VERSION([$DOCBOOK_NS_XSLT_CURRENT_VERSION], [lt], [$1], [ 95 | # version is less than required, so mark it as "no" 96 | DOCBOOK_NS_XSLT_CURRENT_VERSION=no 97 | ]) 98 | 99 | if test x"$DOCBOOK_NS_XSLT_CURRENT_VERSION" = x"no"; then 100 | AC_MSG_RESULT([no]) 101 | else 102 | AC_MSG_RESULT([yes ($DOCBOOK_NS_XSLT_CURRENT_VERSION)]) 103 | fi 104 | fi 105 | ]) 106 | -------------------------------------------------------------------------------- /libmy/m4/my_code_coverage.m4: -------------------------------------------------------------------------------- 1 | # SYNOPSIS 2 | # 3 | # MY_CODE_COVERAGE() 4 | # 5 | # DESCRIPTION 6 | # 7 | # Defines CODE_COVERAGE_CFLAGS and CODE_COVERAGE_LDFLAGS which should be 8 | # included in the CFLAGS and LIBS/LDFLAGS variables of every build target 9 | # (program or library) which should be built with code coverage support. 10 | # Also defines CODE_COVERAGE_RULES which should be substituted in your 11 | # Makefile; and $enable_code_coverage which can be used in subsequent 12 | # configure output. CODE_COVERAGE_ENABLED is defined and substituted, and 13 | # corresponds to the value of the --enable-code-coverage option, which 14 | # defaults to being disabled. 15 | # 16 | # Usage example: 17 | # configure.ac: 18 | # MY_CODE_COVERAGE 19 | # 20 | # Makefile.am: 21 | # @CODE_COVERAGE_RULES@ 22 | # my_program_LIBS = … $(CODE_COVERAGE_LDFLAGS) … 23 | # my_program_CFLAGS = … $(CODE_COVERAGE_CFLAGS) … 24 | # 25 | # This results in a “check-code-coverage” rule being added to any Makefile.am 26 | # which includes “@CODE_COVERAGE_RULES@” (assuming the module has been 27 | # configured with --enable-code-coverage). Running `make check-code-coverage` 28 | # in that directory will run the module’s test suite (`make check`) and build 29 | # a code coverage report detailing the code which was touched, then print the 30 | # URI for the report. 31 | # 32 | # LICENSE 33 | # 34 | # Copyright © 2012, 2014 Philip Withnall 35 | # Copyright © 2012 Xan Lopez 36 | # Copyright © 2012 Christian Persch 37 | # Copyright © 2012 Paolo Borelli 38 | # Copyright © 2012 Dan Winship 39 | # 40 | # Derived from Makefile.decl in GLib, originally licenced under LGPLv2.1+. 41 | # This file is licenced under LGPLv2.1+. 42 | 43 | AC_DEFUN([MY_CODE_COVERAGE],[ 44 | dnl Check for --enable-code-coverage 45 | AC_MSG_CHECKING([whether to build with code coverage support]) 46 | AC_ARG_ENABLE([code-coverage], AS_HELP_STRING([--enable-code-coverage], [Whether to enable code coverage support]),, enable_code_coverage=no) 47 | AM_CONDITIONAL([CODE_COVERAGE_ENABLED], [test x$enable_code_coverage = xyes]) 48 | AC_SUBST([CODE_COVERAGE_ENABLED], [$enable_code_coverage]) 49 | AC_MSG_RESULT($enable_code_coverage) 50 | 51 | AS_IF([ test "$enable_code_coverage" = "yes" ], [ 52 | dnl Check if gcc is being used 53 | AS_IF([ test "$GCC" = "no" ], [ 54 | AC_MSG_ERROR([not compiling with gcc, which is required for gcov code coverage]) 55 | ]) 56 | 57 | AC_CHECK_PROG([LCOV], [lcov], [lcov]) 58 | AC_CHECK_PROG([GENHTML], [genhtml], [genhtml]) 59 | 60 | AS_IF([ test -z "$LCOV" ], [ 61 | AC_MSG_ERROR([The lcov program was not found. Please install lcov!]) 62 | ]) 63 | 64 | AS_IF([ test -z "$GENHTML" ], [ 65 | AC_MSG_ERROR([The genhtml program was not found. Please install lcov!]) 66 | ]) 67 | 68 | dnl Build the code coverage flags 69 | CODE_COVERAGE_CFLAGS="-O0 -g --coverage" 70 | CODE_COVERAGE_LDFLAGS="--coverage" 71 | 72 | AC_SUBST([CODE_COVERAGE_CFLAGS]) 73 | AC_SUBST([CODE_COVERAGE_LDFLAGS]) 74 | 75 | dnl Strip optimisation flags 76 | changequote({,}) 77 | CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9]*//g'` 78 | changequote([,]) 79 | ]) 80 | 81 | CODE_COVERAGE_RULES=' 82 | # Code coverage 83 | # 84 | # Optional: 85 | # - CODE_COVERAGE_DIRECTORY: Top-level directory for code coverage reporting. 86 | # (Default: $(top_builddir)) 87 | # - CODE_COVERAGE_OUTPUT_FILE: Filename and path for the .info file generated 88 | # by lcov for code coverage. (Default: 89 | # $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info) 90 | # - CODE_COVERAGE_OUTPUT_DIRECTORY: Directory for generated code coverage 91 | # reports to be created. (Default: 92 | # $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage) 93 | # - CODE_COVERAGE_LCOV_OPTIONS: Extra options to pass to the lcov instance. 94 | # (Default: empty) 95 | # - CODE_COVERAGE_GENHTML_OPTIONS: Extra options to pass to the genhtml 96 | # instance. (Default: empty) 97 | # - CODE_COVERAGE_IGNORE_PATTERN: Extra glob pattern of files to ignore 98 | # 99 | # The generated report will be titled using the $(PACKAGE_NAME) and 100 | # $(PACKAGE_VERSION). In order to add the current git hash to the title, 101 | # use the git-version-gen script, available online. 102 | 103 | # Optional variables 104 | CODE_COVERAGE_DIRECTORY ?= $(abs_top_builddir) 105 | CODE_COVERAGE_OUTPUT_FILE ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info 106 | CODE_COVERAGE_OUTPUT_DIRECTORY ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage 107 | CODE_COVERAGE_LCOV_OPTIONS ?= 108 | CODE_COVERAGE_GENHTML_OPTIONS ?= 109 | CODE_COVERAGE_IGNORE_PATTERN ?= 110 | 111 | code_coverage_quiet = $(code_coverage_quiet_$(V)) 112 | code_coverage_quiet_ = $(code_coverage_quiet_$(AM_DEFAULT_VERBOSITY)) 113 | code_coverage_quiet_0 = --quiet 114 | 115 | # Use recursive makes in order to ignore errors during check 116 | check-code-coverage: 117 | ifeq ($(CODE_COVERAGE_ENABLED),yes) 118 | -$(MAKE) $(AM_MAKEFLAGS) -k check 119 | $(MAKE) $(AM_MAKEFLAGS) code-coverage-capture 120 | else 121 | @echo "Need to reconfigure with --enable-code-coverage" 122 | endif 123 | 124 | # Capture code coverage data 125 | code-coverage-capture: code-coverage-capture-hook 126 | ifeq ($(CODE_COVERAGE_ENABLED),yes) 127 | $(LCOV) $(code_coverage_quiet) --directory $(CODE_COVERAGE_DIRECTORY) --capture --output-file "$(CODE_COVERAGE_OUTPUT_FILE).tmp" --test-name "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" --no-checksum --compat-libtool $(CODE_COVERAGE_LCOV_OPTIONS) 128 | $(LCOV) $(code_coverage_quiet) --directory $(CODE_COVERAGE_DIRECTORY) --remove "$(CODE_COVERAGE_OUTPUT_FILE).tmp" "/tmp/*" $(CODE_COVERAGE_IGNORE_PATTERN) --output-file "$(CODE_COVERAGE_OUTPUT_FILE)" 129 | -@rm -f $(CODE_COVERAGE_OUTPUT_FILE).tmp 130 | LANG=C $(GENHTML) $(code_coverage_quiet) --prefix $(CODE_COVERAGE_DIRECTORY) --output-directory "$(CODE_COVERAGE_OUTPUT_DIRECTORY)" --title "$(PACKAGE_NAME)-$(PACKAGE_VERSION) Code Coverage" --legend --show-details "$(CODE_COVERAGE_OUTPUT_FILE)" $(CODE_COVERAGE_GENHTML_OPTIONS) 131 | @echo "file://$(abs_builddir)/$(CODE_COVERAGE_OUTPUT_DIRECTORY)/index.html" 132 | else 133 | @echo "Need to reconfigure with --enable-code-coverage" 134 | endif 135 | 136 | # Hook rule executed before code-coverage-capture, overridable by the user 137 | code-coverage-capture-hook: 138 | 139 | ifeq ($(CODE_COVERAGE_ENABLED),yes) 140 | clean: code-coverage-clean 141 | code-coverage-clean: 142 | -$(LCOV) --directory $(CODE_COVERAGE_DIRECTORY) -z 143 | -rm -rf $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_FILE).tmp $(CODE_COVERAGE_OUTPUT_DIRECTORY) 144 | -find . -name "*.gcda" -o -name "*.gcov" -delete 145 | endif 146 | 147 | GITIGNOREFILES ?= 148 | GITIGNOREFILES += $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_DIRECTORY) 149 | 150 | DISTCHECK_CONFIGURE_FLAGS ?= 151 | DISTCHECK_CONFIGURE_FLAGS += --disable-code-coverage 152 | 153 | .PHONY: check-code-coverage code-coverage-capture code-coverage-capture-hook code-coverage-clean 154 | ' 155 | 156 | AC_SUBST([CODE_COVERAGE_RULES]) 157 | m4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([CODE_COVERAGE_RULES])]) 158 | ]) 159 | -------------------------------------------------------------------------------- /libmy/m4/my_pkg_config_files.m4: -------------------------------------------------------------------------------- 1 | # SYNOPSIS 2 | # 3 | # my_PKG_CONFIG_FILES(pc-files-variable, pc-files-value) 4 | # 5 | # DESCRIPTION 6 | # 7 | # Wrapper for PKG_INSTALLDIR that allows disabling the installation of .pc 8 | # files when explicitly configured with --without-pkgconfigdir. It also 9 | # selects a more sensible default for pkgconfigdir on platforms that place 10 | # pkg-config files in a "libdata" directory. 11 | # 12 | # If .pc file installation is enabled, pc-files-variable will be set to 13 | # pc-files-value. 14 | # 15 | # Example: 16 | # 17 | # In configure.ac: 18 | # 19 | # my_PKG_CONFIG_FILES([LIBEXAMPLE_PC], [src/libexample.pc]) 20 | # 21 | # In Makefile.am: 22 | # 23 | # pkgconfig_DATA = ${LIBEXAMPLE_PC} 24 | # CLEANFILES += ${LIBEXAMPLE_PC} 25 | # 26 | # Here, ${LIBEXAMPLE_PC} will normally expand to "src/libexample.pc", unless 27 | # configure was called with --without-pkgconfigdir, in which case it will 28 | # expand to "". 29 | # 30 | 31 | AC_DEFUN([my_PKG_CONFIG_FILES], 32 | [ 33 | PKG_PROG_PKG_CONFIG 34 | 35 | pkgconfig_dir='${libdir}/pkgconfig' 36 | if test -n "$PKG_CONFIG"; then 37 | if $PKG_CONFIG --variable=pc_path pkg-config 2>/dev/null | grep -q /libdata/; then 38 | pkgconfig_dir='${prefix}/libdata/pkgconfig' 39 | fi 40 | fi 41 | PKG_INSTALLDIR([$pkgconfig_dir]) 42 | 43 | if test "x$pkgconfigdir" != "xno"; then 44 | if test -z "$PKG_CONFIG"; then 45 | AC_MSG_ERROR([pkg-config is required!]) 46 | fi 47 | $1=$2 48 | AC_SUBST([$1]) 49 | fi 50 | ]) 51 | -------------------------------------------------------------------------------- /libmy/m4/pcap.m4: -------------------------------------------------------------------------------- 1 | AC_DEFUN([MY_CHECK_LIBPCAP], [ 2 | libpcap_CFLAGS="" 3 | libpcap_LIBS="-lpcap" 4 | 5 | AC_ARG_WITH( 6 | [libpcap], 7 | AC_HELP_STRING([--with-libpcap=DIR], [libpcap installation path]), 8 | [], 9 | [withval="yes"] 10 | ) 11 | if test "$withval" = "yes"; then 12 | withval="/usr /usr/local" 13 | fi 14 | 15 | libpcap_dir="" 16 | 17 | AC_MSG_CHECKING([for libpcap headers]) 18 | for dir in $withval; do 19 | if test -f "$dir/include/pcap.h"; then 20 | libpcap_dir="$dir" 21 | if test "$dir" != "/usr"; then 22 | libpcap_CFLAGS="-I$dir/include" 23 | fi 24 | break 25 | fi 26 | done 27 | if test -n "$libpcap_dir"; then 28 | AC_MSG_RESULT([$libpcap_dir]) 29 | else 30 | AC_MSG_ERROR([cannot find pcap.h in $withval]) 31 | fi 32 | 33 | save_LDFLAGS="$LDFLAGS" 34 | save_LIBS="$LIBS" 35 | if test "$libpcap_dir" != "/usr"; then 36 | libpcap_LIBS="$libpcap_LIBS -L$libpcap_dir/lib" 37 | LDFLAGS="-L$libpcap_dir/lib" 38 | fi 39 | AC_CHECK_LIB( 40 | [pcap], 41 | [pcap_open_offline], 42 | [], 43 | [AC_MSG_ERROR([required library not found])] 44 | ) 45 | AC_SEARCH_LIBS( 46 | [pcap_create], 47 | [pcap], 48 | AC_DEFINE([HAVE_PCAP_CREATE], [1], [Define to 1 if pcap_create() is available.]) 49 | ) 50 | LDFLAGS="$save_LDFLAGS" 51 | LIBS="$save_LIBS" 52 | 53 | AC_SUBST([libpcap_CFLAGS]) 54 | AC_SUBST([libpcap_LIBS]) 55 | ]) 56 | -------------------------------------------------------------------------------- /libmy/m4/pkg.m4: -------------------------------------------------------------------------------- 1 | # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- 2 | # serial 1 (pkg-config-0.24) 3 | # 4 | # Copyright © 2004 Scott James Remnant . 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, write to the Free Software 18 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | # 20 | # As a special exception to the GNU General Public License, if you 21 | # distribute this file as part of a program that contains a 22 | # configuration script generated by Autoconf, you may include it under 23 | # the same distribution terms that you use for the rest of that program. 24 | 25 | # PKG_PROG_PKG_CONFIG([MIN-VERSION]) 26 | # ---------------------------------- 27 | AC_DEFUN([PKG_PROG_PKG_CONFIG], 28 | [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) 29 | m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) 30 | m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) 31 | AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) 32 | AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) 33 | AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) 34 | 35 | if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then 36 | AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) 37 | fi 38 | if test -n "$PKG_CONFIG"; then 39 | _pkg_min_version=m4_default([$1], [0.9.0]) 40 | AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) 41 | if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then 42 | AC_MSG_RESULT([yes]) 43 | else 44 | AC_MSG_RESULT([no]) 45 | PKG_CONFIG="" 46 | fi 47 | fi[]dnl 48 | ])# PKG_PROG_PKG_CONFIG 49 | 50 | # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) 51 | # 52 | # Check to see whether a particular set of modules exists. Similar 53 | # to PKG_CHECK_MODULES(), but does not set variables or print errors. 54 | # 55 | # Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) 56 | # only at the first occurence in configure.ac, so if the first place 57 | # it's called might be skipped (such as if it is within an "if", you 58 | # have to call PKG_CHECK_EXISTS manually 59 | # -------------------------------------------------------------- 60 | AC_DEFUN([PKG_CHECK_EXISTS], 61 | [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl 62 | if test -n "$PKG_CONFIG" && \ 63 | AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then 64 | m4_default([$2], [:]) 65 | m4_ifvaln([$3], [else 66 | $3])dnl 67 | fi]) 68 | 69 | # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) 70 | # --------------------------------------------- 71 | m4_define([_PKG_CONFIG], 72 | [if test -n "$$1"; then 73 | pkg_cv_[]$1="$$1" 74 | elif test -n "$PKG_CONFIG"; then 75 | PKG_CHECK_EXISTS([$3], 76 | [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` 77 | test "x$?" != "x0" && pkg_failed=yes ], 78 | [pkg_failed=yes]) 79 | else 80 | pkg_failed=untried 81 | fi[]dnl 82 | ])# _PKG_CONFIG 83 | 84 | # _PKG_SHORT_ERRORS_SUPPORTED 85 | # ----------------------------- 86 | AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], 87 | [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) 88 | if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then 89 | _pkg_short_errors_supported=yes 90 | else 91 | _pkg_short_errors_supported=no 92 | fi[]dnl 93 | ])# _PKG_SHORT_ERRORS_SUPPORTED 94 | 95 | 96 | # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], 97 | # [ACTION-IF-NOT-FOUND]) 98 | # 99 | # 100 | # Note that if there is a possibility the first call to 101 | # PKG_CHECK_MODULES might not happen, you should be sure to include an 102 | # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac 103 | # 104 | # 105 | # -------------------------------------------------------------- 106 | AC_DEFUN([PKG_CHECK_MODULES], 107 | [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl 108 | AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl 109 | AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl 110 | 111 | pkg_failed=no 112 | AC_MSG_CHECKING([for $1]) 113 | 114 | _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) 115 | _PKG_CONFIG([$1][_LIBS], [libs], [$2]) 116 | 117 | m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS 118 | and $1[]_LIBS to avoid the need to call pkg-config. 119 | See the pkg-config man page for more details.]) 120 | 121 | if test $pkg_failed = yes; then 122 | AC_MSG_RESULT([no]) 123 | _PKG_SHORT_ERRORS_SUPPORTED 124 | if test $_pkg_short_errors_supported = yes; then 125 | $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` 126 | else 127 | $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` 128 | fi 129 | # Put the nasty error message in config.log where it belongs 130 | echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD 131 | 132 | m4_default([$4], [AC_MSG_ERROR( 133 | [Package requirements ($2) were not met: 134 | 135 | $$1_PKG_ERRORS 136 | 137 | Consider adjusting the PKG_CONFIG_PATH environment variable if you 138 | installed software in a non-standard prefix. 139 | 140 | _PKG_TEXT])[]dnl 141 | ]) 142 | elif test $pkg_failed = untried; then 143 | AC_MSG_RESULT([no]) 144 | m4_default([$4], [AC_MSG_FAILURE( 145 | [The pkg-config script could not be found or is too old. Make sure it 146 | is in your PATH or set the PKG_CONFIG environment variable to the full 147 | path to pkg-config. 148 | 149 | _PKG_TEXT 150 | 151 | To get pkg-config, see .])[]dnl 152 | ]) 153 | else 154 | $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS 155 | $1[]_LIBS=$pkg_cv_[]$1[]_LIBS 156 | AC_MSG_RESULT([yes]) 157 | $3 158 | fi[]dnl 159 | ])# PKG_CHECK_MODULES 160 | 161 | 162 | # PKG_INSTALLDIR(DIRECTORY) 163 | # ------------------------- 164 | # Substitutes the variable pkgconfigdir as the location where a module 165 | # should install pkg-config .pc files. By default the directory is 166 | # $libdir/pkgconfig, but the default can be changed by passing 167 | # DIRECTORY. The user can override through the --with-pkgconfigdir 168 | # parameter. 169 | AC_DEFUN([PKG_INSTALLDIR], 170 | [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) 171 | m4_pushdef([pkg_description], 172 | [pkg-config installation directory @<:@]pkg_default[@:>@]) 173 | AC_ARG_WITH([pkgconfigdir], 174 | [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, 175 | [with_pkgconfigdir=]pkg_default) 176 | AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) 177 | m4_popdef([pkg_default]) 178 | m4_popdef([pkg_description]) 179 | ]) dnl PKG_INSTALLDIR 180 | 181 | 182 | # PKG_NOARCH_INSTALLDIR(DIRECTORY) 183 | # ------------------------- 184 | # Substitutes the variable noarch_pkgconfigdir as the location where a 185 | # module should install arch-independent pkg-config .pc files. By 186 | # default the directory is $datadir/pkgconfig, but the default can be 187 | # changed by passing DIRECTORY. The user can override through the 188 | # --with-noarch-pkgconfigdir parameter. 189 | AC_DEFUN([PKG_NOARCH_INSTALLDIR], 190 | [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) 191 | m4_pushdef([pkg_description], 192 | [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) 193 | AC_ARG_WITH([noarch-pkgconfigdir], 194 | [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, 195 | [with_noarch_pkgconfigdir=]pkg_default) 196 | AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) 197 | m4_popdef([pkg_default]) 198 | m4_popdef([pkg_description]) 199 | ]) dnl PKG_NOARCH_INSTALLDIR 200 | 201 | 202 | # PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, 203 | # [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) 204 | # ------------------------------------------- 205 | # Retrieves the value of the pkg-config variable for the given module. 206 | AC_DEFUN([PKG_CHECK_VAR], 207 | [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl 208 | AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl 209 | 210 | _PKG_CONFIG([$1], [variable="][$3]["], [$2]) 211 | AS_VAR_COPY([$1], [pkg_cv_][$1]) 212 | 213 | AS_VAR_IF([$1], [""], [$5], [$4])dnl 214 | ])# PKG_CHECK_VAR 215 | -------------------------------------------------------------------------------- /libmy/m4/protobuf-c.m4: -------------------------------------------------------------------------------- 1 | AC_DEFUN([MY_CHECK_LIBPROTOBUF_C], [ 2 | libprotobuf_c_CFLAGS="" 3 | libprotobuf_c_LIBS="-lprotobuf-c" 4 | 5 | AC_ARG_WITH( 6 | [libprotobuf_c], 7 | AC_HELP_STRING([--with-libprotobuf_c=DIR], [libprotobuf-c installation path]), 8 | [], 9 | [withval="yes"] 10 | ) 11 | if test "$withval" = "yes"; then 12 | withval="/usr /usr/local" 13 | fi 14 | 15 | libprotobuf_c_dir="" 16 | 17 | AC_MSG_CHECKING([for libprotobuf-c headers]) 18 | for dir in $withval; do 19 | if test -f "$dir/include/protobuf-c/protobuf-c.h"; then 20 | libprotobuf_c_dir="$dir" 21 | if test "$dir" != "/usr"; then 22 | libprotobuf_c_CFLAGS="-I$dir/include" 23 | fi 24 | break 25 | elif test -f "$dir/include/google/protobuf-c/protobuf-c.h"; then 26 | libprotobuf_c_dir="$dir" 27 | libprotobuf_c_CFLAGS="-I$dir/include/google" 28 | break 29 | fi 30 | done 31 | if test -n "$libprotobuf_c_dir"; then 32 | AC_MSG_RESULT([$libprotobuf_c_dir]) 33 | else 34 | AC_MSG_ERROR([cannot find protobuf-c.h in $withval]) 35 | fi 36 | 37 | save_LDFLAGS="$LDFLAGS" 38 | save_LIBS="$LIBS" 39 | if test "$libprotobuf_c_dir" != "/usr"; then 40 | libprotobuf_c_LIBS="$libprotobuf_c_LIBS -L$libprotobuf_c_dir/lib" 41 | LDFLAGS="-L$libprotobuf_c_dir/lib" 42 | fi 43 | AC_CHECK_LIB( 44 | [protobuf-c], 45 | [protobuf_c_message_pack], 46 | [], 47 | [AC_MSG_ERROR([required library not found])] 48 | ) 49 | LDFLAGS="$save_LDFLAGS" 50 | LIBS="$save_LIBS" 51 | 52 | AC_SUBST([libprotobuf_c_CFLAGS]) 53 | AC_SUBST([libprotobuf_c_LIBS]) 54 | 55 | AC_PATH_PROG([PROTOC_C], [protoc-c]) 56 | if test -z "$PROTOC_C"; then 57 | AC_MSG_ERROR([The protoc-c program was not found. Please install the protobuf-c compiler!]) 58 | fi 59 | ]) 60 | -------------------------------------------------------------------------------- /libmy/my_alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef MY_ALLOC_H 2 | #define MY_ALLOC_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | static inline void * 9 | my_calloc(size_t nmemb, size_t size) 10 | { 11 | void *ptr = calloc(nmemb, size); 12 | assert(ptr != NULL); 13 | return (ptr); 14 | } 15 | 16 | static inline void * 17 | my_malloc(size_t size) 18 | { 19 | void *ptr = malloc(size); 20 | assert(ptr != NULL); 21 | return (ptr); 22 | } 23 | 24 | static inline void * 25 | my_realloc(void *ptr, size_t size) 26 | { 27 | ptr = realloc(ptr, size); 28 | assert(ptr != NULL); 29 | return (ptr); 30 | } 31 | 32 | static inline char * 33 | my_strdup(const char *s) 34 | { 35 | char *ptr = strdup(s); 36 | assert(ptr != NULL); 37 | return (ptr); 38 | } 39 | 40 | #define my_free(ptr) do { free(ptr); (ptr) = NULL; } while (0) 41 | 42 | #if defined(MY_ALLOC_WARN_DEPRECATED) 43 | 44 | static inline void *my_calloc_deprecated(size_t, size_t) 45 | __attribute__ ((deprecated("use my_calloc, not calloc"))); 46 | 47 | static inline void *my_malloc_deprecated(size_t) 48 | __attribute__ ((deprecated("use my_malloc, not malloc"))); 49 | 50 | static inline void *my_realloc_deprecated(void *, size_t) 51 | __attribute__ ((deprecated("use my_realloc, not realloc"))); 52 | 53 | static inline void * 54 | my_calloc_deprecated(size_t nmemb, size_t size) 55 | { 56 | return calloc(nmemb, size); 57 | } 58 | 59 | static inline void * 60 | my_malloc_deprecated(size_t size) 61 | { 62 | return malloc(size); 63 | } 64 | 65 | static inline void * 66 | my_realloc_deprecated(void *ptr, size_t size) 67 | { 68 | return realloc(ptr, size); 69 | } 70 | 71 | #define calloc my_calloc_deprecated 72 | #define malloc my_malloc_deprecated 73 | #define realloc my_realloc_deprecated 74 | 75 | #endif /* MY_ALLOC_WARN_DEPRECATED */ 76 | 77 | #endif /* MY_ALLOC_H */ 78 | -------------------------------------------------------------------------------- /libmy/my_memory_barrier.h: -------------------------------------------------------------------------------- 1 | #ifndef MY_MEMORY_BARRIER_H 2 | #define MY_MEMORY_BARRIER_H 3 | 4 | #if defined(__GNUC__) 5 | # if defined(__x86_64__) 6 | # define MY_HAVE_MEMORY_BARRIERS 1 7 | # define smp_mb() asm volatile("mfence" ::: "memory") 8 | # define smp_rmb() asm volatile("" ::: "memory") 9 | # define smp_wmb() asm volatile("" ::: "memory") 10 | # elif defined(__ia64__) 11 | # define MY_HAVE_MEMORY_BARRIERS 1 12 | # define smp_mb() asm volatile ("mf" ::: "memory") 13 | # define smp_rmb() asm volatile ("mf" ::: "memory") 14 | # define smp_wmb() asm volatile ("mf" ::: "memory") 15 | # endif 16 | #endif 17 | 18 | #endif /* MY_MEMORY_BARRIER_H */ 19 | -------------------------------------------------------------------------------- /libmy/my_queue.h: -------------------------------------------------------------------------------- 1 | #ifndef MY_QUEUE_H 2 | #define MY_QUEUE_H 3 | 4 | #include 5 | 6 | /** 7 | * \file 8 | * 9 | * Fixed-size single-producer / single-consumer queue. 10 | * 11 | * This is a generic queue that supports a single producer thread and a 12 | * single consumer thread. The implementation uses a fixed power-of-2 size 13 | * circular buffer. 14 | * 15 | * The my_queue_insert() and my_queue_remove() functions are "non-blocking"; 16 | * that is, the policies for queue full / queue empty conditions are left to 17 | * the caller. These functions return a boolean indicating whether the queue 18 | * operation succeeded or not. For example, a producer that spins until an 19 | * element is successfully enqueued might look like: 20 | * 21 | * void *item; 22 | * produce_item(&item); 23 | * while (!my_queue_insert(q, item, NULL)); 24 | * 25 | * And a consumer that spins until an element is successfully dequeued 26 | * might look like: 27 | * 28 | * void *item; 29 | * while (!my_queue_remove(q, &item, NULL)); 30 | * consume_item(item); 31 | * 32 | * The my_queue_insert() and my_queue_remove() functions take an optional third 33 | * parameter for returning the spaces remaining in the queue or the count of 34 | * elements remaining, respectively. This allows for more complicated 35 | * coordination between producer and consumer, for instance a consumer thread 36 | * that sleeps when the queue is empty and is woken by the producer when it 37 | * adds an element to an empty queue. 38 | */ 39 | 40 | struct my_queue; 41 | 42 | /** 43 | * Initialize a new queue. 44 | * 45 | * \param[in] num_entries Number of elements in the queue. Must be >=2, and a power-of-2. 46 | * \param[in] size_entry Size in bytes of each queue entry. 47 | * \return Opaque pointer that is NULL on failure or non-NULL on success. 48 | */ 49 | struct my_queue * 50 | my_queue_init(unsigned num_entries, unsigned size_entry); 51 | 52 | /** 53 | * Destroy a queue. 54 | */ 55 | void 56 | my_queue_destroy(struct my_queue **q); 57 | 58 | /** 59 | * Describe the queue implementation type. 60 | */ 61 | const char * 62 | my_queue_impl_type(void); 63 | 64 | /** 65 | * Insert an element into the queue. 66 | * 67 | * \param[in] q Queue object. 68 | * \param[in] elem Element object. 69 | * \param[out] space If non-NULL, pointer to store the number of remaining 70 | * spaces in the queue. 71 | * \return true if the element was inserted into the queue, 72 | * false if the queue is full. 73 | */ 74 | bool 75 | my_queue_insert(struct my_queue *q, void *elem, unsigned *space); 76 | 77 | /** 78 | * Remove an element from the queue. 79 | * 80 | * \param[in] q Queue object. 81 | * \param[out] elem Where the element object will be copied. 82 | * \param[out] count If non-NULL, pointer to store the count of elements 83 | * remaining in the queue. 84 | * \return true if an element was removed from the queue, 85 | * false if the queue is empty. 86 | */ 87 | bool 88 | my_queue_remove(struct my_queue *q, void *elem, unsigned *count); 89 | 90 | struct my_queue_ops { 91 | struct my_queue *(*init)(unsigned, unsigned); 92 | void (*destroy)(struct my_queue **); 93 | const char *(*impl_type)(void); 94 | bool (*insert)(struct my_queue *, void *, unsigned *); 95 | bool (*remove)(struct my_queue *, void *, unsigned *); 96 | }; 97 | 98 | #endif /* MY_QUEUE_H */ 99 | -------------------------------------------------------------------------------- /libmy/my_queue_mb.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, 2014 by Farsight Security, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #include "my_memory_barrier.h" 26 | 27 | #ifdef MY_HAVE_MEMORY_BARRIERS 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include "my_alloc.h" 34 | 35 | #include "my_queue.h" 36 | 37 | #define MY_ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) 38 | 39 | struct my_queue * 40 | my_queue_mb_init(unsigned, unsigned); 41 | 42 | void 43 | my_queue_mb_destroy(struct my_queue **); 44 | 45 | const char * 46 | my_queue_mb_impl_type(void); 47 | 48 | bool 49 | my_queue_mb_insert(struct my_queue *, void *, unsigned *); 50 | 51 | bool 52 | my_queue_mb_remove(struct my_queue *, void *, unsigned *); 53 | 54 | struct my_queue { 55 | uint8_t *data; 56 | unsigned num_elems; 57 | unsigned sizeof_elem; 58 | unsigned head; 59 | unsigned tail; 60 | }; 61 | 62 | struct my_queue * 63 | my_queue_mb_init(unsigned num_elems, unsigned sizeof_elem) 64 | { 65 | struct my_queue *q; 66 | if (num_elems < 2 || ((num_elems - 1) & num_elems) != 0) 67 | return (NULL); 68 | q = my_calloc(1, sizeof(*q)); 69 | q->num_elems = num_elems; 70 | q->sizeof_elem = sizeof_elem; 71 | q->data = my_calloc(q->num_elems, q->sizeof_elem); 72 | return (q); 73 | } 74 | 75 | void 76 | my_queue_mb_destroy(struct my_queue **q) 77 | { 78 | if (*q) { 79 | free((*q)->data); 80 | free(*q); 81 | *q = NULL; 82 | } 83 | } 84 | 85 | const char * 86 | my_queue_mb_impl_type(void) 87 | { 88 | return ("memory barrier"); 89 | } 90 | 91 | static inline unsigned 92 | q_space(unsigned head, unsigned tail, unsigned size) 93 | { 94 | return ((tail - (head + 1)) & (size - 1)); 95 | } 96 | 97 | static inline unsigned 98 | q_count(unsigned head, unsigned tail, unsigned size) 99 | { 100 | return ((head - tail) & (size - 1)); 101 | } 102 | 103 | bool 104 | my_queue_mb_insert(struct my_queue *q, void *item, unsigned *pspace) 105 | { 106 | bool res = false; 107 | unsigned head = q->head; 108 | unsigned tail = MY_ACCESS_ONCE(q->tail); 109 | unsigned space = q_space(head, tail, q->num_elems); 110 | if (space >= 1) { 111 | memcpy(&q->data[head * q->sizeof_elem], item, q->sizeof_elem); 112 | smp_wmb(); 113 | q->head = (head + 1) & (q->num_elems - 1); 114 | smp_wmb(); 115 | res = true; 116 | space--; 117 | } 118 | if (pspace != NULL) 119 | *pspace = space; 120 | return (res); 121 | } 122 | 123 | bool 124 | my_queue_mb_remove(struct my_queue *q, void *item, unsigned *pcount) 125 | { 126 | bool res = false; 127 | unsigned head = MY_ACCESS_ONCE(q->head); 128 | unsigned tail = q->tail; 129 | unsigned count = q_count(head, tail, q->num_elems); 130 | if (count >= 1) { 131 | memcpy(item, &q->data[tail * q->sizeof_elem], q->sizeof_elem); 132 | smp_mb(); 133 | q->tail = (tail + 1) & (q->num_elems - 1); 134 | res = true; 135 | count--; 136 | } 137 | if (pcount != NULL) 138 | *pcount = count; 139 | return (res); 140 | } 141 | 142 | const struct my_queue_ops my_queue_mb_ops = { 143 | .init = 144 | my_queue_mb_init, 145 | .destroy = 146 | my_queue_mb_destroy, 147 | .impl_type = 148 | my_queue_mb_impl_type, 149 | .insert = 150 | my_queue_mb_insert, 151 | .remove = 152 | my_queue_mb_remove, 153 | }; 154 | 155 | #endif /* MY_HAVE_MEMORY_BARRIERS */ 156 | -------------------------------------------------------------------------------- /libmy/my_queue_mutex.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, 2014 by Farsight Security, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "my_alloc.h" 32 | 33 | #include "my_queue.h" 34 | 35 | #if defined(__GNUC__) 36 | # define _aligned __attribute__((aligned(64))) 37 | #else 38 | # define _aligned 39 | #endif 40 | 41 | struct my_queue { 42 | uint8_t *data; 43 | unsigned num_elems; 44 | unsigned sizeof_elem; 45 | unsigned head; 46 | unsigned tail; 47 | pthread_mutex_t lock _aligned; 48 | }; 49 | 50 | struct my_queue * 51 | my_queue_mutex_init(unsigned, unsigned); 52 | 53 | void 54 | my_queue_mutex_destroy(struct my_queue **); 55 | 56 | const char * 57 | my_queue_mutex_impl_type(void); 58 | 59 | bool 60 | my_queue_mutex_insert(struct my_queue *, void *, unsigned *); 61 | 62 | bool 63 | my_queue_mutex_remove(struct my_queue *, void *, unsigned *); 64 | 65 | struct my_queue * 66 | my_queue_mutex_init(unsigned num_elems, unsigned sizeof_elem) 67 | { 68 | struct my_queue *q; 69 | if (num_elems < 2 || ((num_elems - 1) & num_elems) != 0) 70 | return (NULL); 71 | q = my_calloc(1, sizeof(*q)); 72 | q->num_elems = num_elems; 73 | q->sizeof_elem = sizeof_elem; 74 | q->data = my_calloc(q->num_elems, q->sizeof_elem); 75 | int rc = pthread_mutex_init(&q->lock, NULL); 76 | assert(rc == 0); 77 | return (q); 78 | } 79 | 80 | void 81 | my_queue_mutex_destroy(struct my_queue **q) 82 | { 83 | if (*q) { 84 | pthread_mutex_destroy(&(*q)->lock); 85 | free((*q)->data); 86 | free(*q); 87 | *q = NULL; 88 | } 89 | } 90 | 91 | const char * 92 | my_queue_mutex_impl_type(void) 93 | { 94 | return ("pthread mutex"); 95 | } 96 | 97 | static inline void 98 | q_lock(struct my_queue *q) 99 | { 100 | int rc = pthread_mutex_lock(&q->lock); 101 | assert(rc == 0); 102 | } 103 | 104 | static inline void 105 | q_unlock(struct my_queue *q) 106 | { 107 | int rc = pthread_mutex_unlock(&q->lock); 108 | assert(rc == 0); 109 | } 110 | 111 | static inline unsigned 112 | q_space(unsigned head, unsigned tail, unsigned size) 113 | { 114 | return ((tail - (head + 1)) & (size - 1)); 115 | } 116 | 117 | static inline unsigned 118 | q_count(unsigned head, unsigned tail, unsigned size) 119 | { 120 | return ((head - tail) & (size - 1)); 121 | } 122 | 123 | bool 124 | my_queue_mutex_insert(struct my_queue *q, void *item, unsigned *pspace) 125 | { 126 | q_lock(q); 127 | bool res = false; 128 | unsigned head = q->head; 129 | unsigned tail = q->tail; 130 | unsigned space = q_space(head, tail, q->num_elems); 131 | if (space >= 1) { 132 | memcpy(&q->data[head * q->sizeof_elem], item, q->sizeof_elem); 133 | q->head = (head + 1) & (q->num_elems - 1); 134 | res = true; 135 | space--; 136 | } 137 | q_unlock(q); 138 | if (pspace) 139 | *pspace = space; 140 | return (res); 141 | } 142 | 143 | bool 144 | my_queue_mutex_remove(struct my_queue *q, void *item, unsigned *pcount) 145 | { 146 | q_lock(q); 147 | bool res = false; 148 | unsigned head = q->head; 149 | unsigned tail = q->tail; 150 | unsigned count = q_count(head, tail, q->num_elems); 151 | if (count >= 1) { 152 | memcpy(item, &q->data[tail * q->sizeof_elem], q->sizeof_elem); 153 | q->tail = (tail + 1) & (q->num_elems - 1); 154 | res = true; 155 | count--; 156 | } 157 | q_unlock(q); 158 | if (pcount) 159 | *pcount = count; 160 | return (res); 161 | } 162 | 163 | const struct my_queue_ops my_queue_mutex_ops = { 164 | .init = 165 | my_queue_mutex_init, 166 | .destroy = 167 | my_queue_mutex_destroy, 168 | .impl_type = 169 | my_queue_mutex_impl_type, 170 | .insert = 171 | my_queue_mutex_insert, 172 | .remove = 173 | my_queue_mutex_remove, 174 | }; 175 | -------------------------------------------------------------------------------- /libmy/my_time.h: -------------------------------------------------------------------------------- 1 | #ifndef MY_TIME_H 2 | #define MY_TIME_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #if HAVE_CLOCK_GETTIME 10 | static inline void 11 | my_gettime(clockid_t clk_id, struct timespec *ts) 12 | { 13 | int res; 14 | res = clock_gettime(clk_id, ts); 15 | assert(res == 0); 16 | } 17 | #else 18 | static inline void 19 | my_gettime(int clk_id __attribute__((unused)), struct timespec *ts) 20 | { 21 | struct timeval tv; 22 | int res; 23 | 24 | res = gettimeofday(&tv, NULL); 25 | assert(res == 0); 26 | 27 | ts->tv_sec = tv.tv_sec; 28 | ts->tv_nsec = tv.tv_usec * 1000; 29 | } 30 | #endif 31 | 32 | static inline void 33 | my_timespec_add(const struct timespec *a, struct timespec *b) { 34 | b->tv_sec += a->tv_sec; 35 | b->tv_nsec += a->tv_nsec; 36 | while (b->tv_nsec >= 1000000000) { 37 | b->tv_sec += 1; 38 | b->tv_nsec -= 1000000000; 39 | } 40 | } 41 | 42 | static inline void 43 | my_timespec_sub(const struct timespec *a, struct timespec *b) 44 | { 45 | b->tv_sec -= a->tv_sec; 46 | b->tv_nsec -= a->tv_nsec; 47 | if (b->tv_nsec < 0) { 48 | b->tv_sec -= 1; 49 | b->tv_nsec += 1000000000; 50 | } 51 | } 52 | 53 | static inline double 54 | my_timespec_to_double(const struct timespec *ts) 55 | { 56 | return (ts->tv_sec + ts->tv_nsec / 1E9); 57 | } 58 | 59 | static inline void 60 | my_timespec_from_double(double seconds, struct timespec *ts) { 61 | ts->tv_sec = (time_t) seconds; 62 | ts->tv_nsec = (long) ((seconds - ((int) seconds)) * 1E9); 63 | } 64 | 65 | static inline void 66 | my_nanosleep(const struct timespec *ts) 67 | { 68 | struct timespec rqt, rmt; 69 | 70 | for (rqt = *ts; nanosleep(&rqt, &rmt) < 0 && errno == EINTR; rqt = rmt) 71 | ; 72 | } 73 | 74 | #endif /* MY_TIME_H */ 75 | -------------------------------------------------------------------------------- /libmy/print_string.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 by Farsight Security, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #ifndef MY_PRINT_STRING_H 26 | #define MY_PRINT_STRING_H 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | static inline void 33 | print_string(const void *data, size_t len, FILE *out) 34 | { 35 | uint8_t *str = (uint8_t *) data; 36 | fputc('"', out); 37 | while (len-- != 0) { 38 | unsigned c = *(str++); 39 | if (isprint(c)) { 40 | if (c == '"') 41 | fputs("\\\"", out); 42 | else 43 | fputc(c, out); 44 | } else { 45 | fprintf(out, "\\x%02x", c); 46 | } 47 | } 48 | fputc('"', out); 49 | } 50 | 51 | #endif /* MY_PRINT_STRING_H */ 52 | -------------------------------------------------------------------------------- /libmy/read_bytes.h: -------------------------------------------------------------------------------- 1 | #ifndef MY_READ_BYTES_H 2 | #define MY_READ_BYTES_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static inline bool 10 | read_bytes(int fd, uint8_t *buf, size_t bytes_needed) 11 | { 12 | while (bytes_needed > 0) { 13 | ssize_t bytes_read; 14 | 15 | bytes_read = read(fd, buf, bytes_needed); 16 | if (bytes_read == -1 && errno == EINTR) 17 | continue; 18 | else if (bytes_read <= 0) 19 | return false; 20 | bytes_needed -= bytes_read; 21 | buf += bytes_read; 22 | } 23 | return true; 24 | } 25 | 26 | #endif /* MY_READ_BYTES_H */ 27 | -------------------------------------------------------------------------------- /libmy/ubuf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 by Farsight Security, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #ifndef MY_UBUF_H 26 | #define MY_UBUF_H 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "vector.h" 36 | 37 | VECTOR_GENERATE(ubuf, uint8_t) 38 | 39 | static inline ubuf * 40 | ubuf_new(void) 41 | { 42 | return (ubuf_init(64)); 43 | } 44 | 45 | static inline ubuf * 46 | ubuf_dup_cstr(const char *s) 47 | { 48 | size_t len = strlen(s); 49 | ubuf *u = ubuf_init(len + 1); 50 | ubuf_append(u, (const uint8_t *) s, len); 51 | return (u); 52 | } 53 | 54 | static inline void 55 | ubuf_add_cstr(ubuf *u, const char *s) 56 | { 57 | if (ubuf_size(u) > 0 && ubuf_value(u, ubuf_size(u) - 1) == '\x00') 58 | ubuf_clip(u, ubuf_size(u) - 1); 59 | ubuf_append(u, (const uint8_t *) s, strlen(s)); 60 | } 61 | 62 | static inline void 63 | ubuf_cterm(ubuf *u) 64 | { 65 | if (ubuf_size(u) == 0 || 66 | (ubuf_size(u) > 0 && ubuf_value(u, ubuf_size(u) - 1) != '\x00')) 67 | { 68 | ubuf_append(u, (const uint8_t *) "\x00", 1); 69 | } 70 | } 71 | 72 | static inline char * 73 | ubuf_cstr(ubuf *u) 74 | { 75 | ubuf_cterm(u); 76 | return ((char *) ubuf_data(u)); 77 | } 78 | 79 | static inline void 80 | ubuf_add_fmt(ubuf *u, const char *fmt, ...) 81 | { 82 | va_list args, args_copy; 83 | int status, needed; 84 | 85 | if (ubuf_size(u) > 0 && ubuf_value(u, ubuf_size(u) - 1) == '\x00') 86 | ubuf_clip(u, ubuf_size(u) - 1); 87 | 88 | va_start(args, fmt); 89 | 90 | va_copy(args_copy, args); 91 | needed = vsnprintf(NULL, 0, fmt, args_copy); 92 | assert(needed >= 0); 93 | va_end(args_copy); 94 | 95 | ubuf_reserve(u, ubuf_size(u) + needed + 1); 96 | status = vsnprintf((char *) ubuf_ptr(u), needed + 1, fmt, args); 97 | assert(status >= 0); 98 | ubuf_advance(u, needed); 99 | 100 | va_end(args); 101 | } 102 | 103 | static inline void 104 | ubuf_rstrip(ubuf *u, char s) 105 | { 106 | if (ubuf_size(u) > 0 && 107 | ubuf_value(u, ubuf_size(u) - 1) == ((uint8_t) s)) 108 | { 109 | ubuf_clip(u, ubuf_size(u) - 1); 110 | } 111 | } 112 | 113 | #endif /* MY_UBUF_H */ 114 | -------------------------------------------------------------------------------- /libmy/vector.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2014 by Farsight Security, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #include 26 | 27 | #include "my_alloc.h" 28 | 29 | #define VECTOR_GENERATE(name, type) \ 30 | typedef struct name##__vector { \ 31 | type * _v; \ 32 | type * _p; \ 33 | size_t _n, _n_alloced, _hint; \ 34 | } name; \ 35 | __attribute__((unused)) \ 36 | static inline name * \ 37 | name##_init(unsigned hint) \ 38 | { \ 39 | name *vec; \ 40 | vec = my_calloc(1, sizeof(name)); \ 41 | if (hint == 0) hint = 1; \ 42 | vec->_hint = vec->_n_alloced = hint; \ 43 | vec->_v = my_malloc(vec->_n_alloced * sizeof(type)); \ 44 | vec->_p = &(vec->_v[0]); \ 45 | return (vec); \ 46 | } \ 47 | __attribute__((unused)) \ 48 | static inline void \ 49 | name##_reinit(unsigned hint, name *vec) \ 50 | { \ 51 | if (hint == 0) hint = 1; \ 52 | vec->_hint = vec->_n_alloced = hint; \ 53 | vec->_n = 0; \ 54 | vec->_v = my_malloc(vec->_n_alloced * sizeof(type)); \ 55 | vec->_p = &(vec->_v[0]); \ 56 | } \ 57 | __attribute__((unused)) \ 58 | static inline void \ 59 | name##_detach(name *vec, type **out, size_t *outsz) \ 60 | { \ 61 | *(out) = (vec)->_v; \ 62 | *(outsz) = (vec)->_n; \ 63 | (vec)->_n = 0; \ 64 | (vec)->_n_alloced = (vec)->_hint; \ 65 | (vec)->_v = my_malloc((vec)->_n_alloced * sizeof(type)); \ 66 | (vec)->_p = &(vec->_v[0]); \ 67 | } \ 68 | __attribute__((unused)) \ 69 | static inline void \ 70 | name##_destroy(name **vec) \ 71 | { \ 72 | if (*vec) { \ 73 | my_free((*vec)->_v); \ 74 | my_free((*vec)); \ 75 | } \ 76 | } \ 77 | __attribute__((unused)) \ 78 | static inline void \ 79 | name##_reserve(name *vec, size_t n_elems) \ 80 | { \ 81 | while ((n_elems) > ((vec)->_n_alloced - (vec)->_n)) { \ 82 | (vec)->_n_alloced *= 2; \ 83 | (vec)->_v = my_realloc((vec)->_v, (vec)->_n_alloced \ 84 | * sizeof(type)); \ 85 | (vec)->_p = &((vec)->_v[(vec)->_n]); \ 86 | } \ 87 | } \ 88 | __attribute__((unused)) \ 89 | static inline void \ 90 | name##_add(name *vec, type elem) \ 91 | { \ 92 | while ((vec)->_n + 1 > (vec)->_n_alloced) { \ 93 | (vec)->_n_alloced *= 2; \ 94 | (vec)->_v = my_realloc((vec)->_v, (vec)->_n_alloced \ 95 | * sizeof(type)); \ 96 | (vec)->_p = &((vec)->_v[(vec)->_n]); \ 97 | } \ 98 | (vec)->_v[(vec)->_n] = elem; \ 99 | (vec)->_n += 1; \ 100 | (vec)->_p = &((vec)->_v[(vec)->_n]); \ 101 | } \ 102 | __attribute__((unused)) \ 103 | static inline void \ 104 | name##_append(name *vec, type const *elems, size_t n_elems) \ 105 | { \ 106 | name##_reserve(vec, n_elems); \ 107 | memcpy((vec)->_v + (vec)->_n, elems, (n_elems) * sizeof(type)); \ 108 | (vec)->_n += (n_elems); \ 109 | (vec)->_p = &((vec)->_v[(vec)->_n]); \ 110 | } \ 111 | __attribute__((unused)) \ 112 | static inline void \ 113 | name##_extend(name *vec0, name *vec1) \ 114 | { \ 115 | name##_append(vec0, (vec1)->_v, (vec1)->_n); \ 116 | } \ 117 | __attribute__((unused)) \ 118 | static inline void \ 119 | name##_reset(name *vec) \ 120 | { \ 121 | (vec)->_n = 0; \ 122 | if ((vec)->_n_alloced > (vec)->_hint) { \ 123 | (vec)->_n_alloced = (vec)->_hint; \ 124 | (vec)->_v = my_realloc((vec)->_v, (vec)->_n_alloced \ 125 | * sizeof(type)); \ 126 | } \ 127 | (vec)->_p = &(vec->_v[0]); \ 128 | } \ 129 | __attribute__((unused)) \ 130 | static inline void \ 131 | name##_clip(name *vec, size_t n_elems) \ 132 | { \ 133 | if (n_elems < (vec)->_n) { \ 134 | (vec)->_n = n_elems; \ 135 | (vec)->_p = &((vec)->_v[(vec)->_n]); \ 136 | } \ 137 | } \ 138 | __attribute__((unused)) \ 139 | static inline size_t \ 140 | name##_bytes(name *vec) \ 141 | { \ 142 | return ((vec)->_n * sizeof(type)); \ 143 | } \ 144 | __attribute__((unused)) \ 145 | static inline size_t \ 146 | name##_size(name *vec) \ 147 | { \ 148 | return ((vec)->_n); \ 149 | } \ 150 | __attribute__((unused)) \ 151 | static inline type \ 152 | name##_value(name *vec, size_t i) \ 153 | { \ 154 | assert(i < (vec)->_n); \ 155 | return ((vec)->_v[i]); \ 156 | } \ 157 | __attribute__((unused)) \ 158 | static inline type * \ 159 | name##_ptr(name *vec) \ 160 | { \ 161 | return ((vec)->_p); \ 162 | } \ 163 | __attribute__((unused)) \ 164 | static inline type * \ 165 | name##_data(name *vec) \ 166 | { \ 167 | return ((vec)->_v); \ 168 | } \ 169 | __attribute__((unused)) \ 170 | static inline void \ 171 | name##_advance(name *vec, size_t x) \ 172 | { \ 173 | assert(x <= ((vec)->_n_alloced - (vec)->_n)); \ 174 | (vec)->_n += x; \ 175 | (vec)->_p = &((vec)->_v[(vec)->_n]); \ 176 | } 177 | -------------------------------------------------------------------------------- /m4/.gitignore: -------------------------------------------------------------------------------- 1 | libtool.m4 2 | ltoptions.m4 3 | ltsugar.m4 4 | ltversion.m4 5 | lt~obsolete.m4 6 | -------------------------------------------------------------------------------- /m4/ax_pthread.m4: -------------------------------------------------------------------------------- 1 | ../libmy/m4/ax_pthread.m4 -------------------------------------------------------------------------------- /m4/ld-version-script.m4: -------------------------------------------------------------------------------- 1 | ../libmy/m4/ld-version-script.m4 -------------------------------------------------------------------------------- /m4/my_code_coverage.m4: -------------------------------------------------------------------------------- 1 | ../libmy/m4/my_code_coverage.m4 -------------------------------------------------------------------------------- /m4/my_pkg_config_files.m4: -------------------------------------------------------------------------------- 1 | ../libmy/m4/my_pkg_config_files.m4 -------------------------------------------------------------------------------- /m4/pkg.m4: -------------------------------------------------------------------------------- 1 | ../libmy/m4/pkg.m4 -------------------------------------------------------------------------------- /m4/valgrind-tests.m4: -------------------------------------------------------------------------------- 1 | # valgrind-tests.m4 serial 2 2 | dnl Copyright (C) 2008-2011 Free Software Foundation, Inc. 3 | dnl This file is free software; the Free Software Foundation 4 | dnl gives unlimited permission to copy and/or distribute it, 5 | dnl with or without modifications, as long as this notice is preserved. 6 | 7 | dnl From Simon Josefsson 8 | 9 | # gl_VALGRIND_TESTS() 10 | # ------------------- 11 | # Check if valgrind is available, and set VALGRIND to it if available. 12 | AC_DEFUN([gl_VALGRIND_TESTS], 13 | [ 14 | AC_ARG_ENABLE(valgrind-tests, 15 | AS_HELP_STRING([--enable-valgrind-tests], 16 | [run self tests under valgrind]), 17 | [opt_valgrind_tests=$enableval], [opt_valgrind_tests=no]) 18 | 19 | # Run self-tests under valgrind? 20 | if test "$opt_valgrind_tests" = "yes" && test "$cross_compiling" = no; then 21 | AC_CHECK_PROGS(VALGRIND, valgrind) 22 | fi 23 | 24 | if test -n "$VALGRIND" && $VALGRIND -q true > /dev/null 2>&1; then 25 | opt_valgrind_tests=yes 26 | VALGRIND="$VALGRIND -q --error-exitcode=1 --leak-check=full \ 27 | --trace-children=yes --trace-children-skip=/usr/*,/bin/*" 28 | else 29 | opt_valgrind_tests=no 30 | VALGRIND= 31 | fi 32 | 33 | AC_MSG_CHECKING([whether self tests are run under valgrind]) 34 | AC_MSG_RESULT($opt_valgrind_tests) 35 | ]) 36 | -------------------------------------------------------------------------------- /man/fstrm_capture.1: -------------------------------------------------------------------------------- 1 | .TH fstrm_capture 1 2 | 3 | .SH NAME 4 | 5 | fstrm_capture \- Receive and save Frame Streams data from a socket. 6 | 7 | .SH SYNOPSIS 8 | 9 | .B fstrm_capture -t \fIcontent-type\fB -w \fIfilename\fB 10 | .br 11 | .B " [ -u \fIsocket-path\fB ] [ -a \fIIP\fB -p \fIport\fB ]" 12 | .br 13 | .B " [ -c \fImax-connections\fB ] [ -b \fIbuffer-size\fB ]" 14 | .br 15 | .B " [ -s \fIseconds\fB ] [ --gmtime ] [ --localtime ]" 16 | .br 17 | .B " [ -d [-d ...] ]" 18 | 19 | .PP 20 | 21 | .B fstrm_capture --type \fIcontent-type\fB --write \fIfilename\fB 22 | .br 23 | .B " [ --unix \fIsocket-path\fB ] [ --tcp \fIIP\fB --port \fIport\fB ]" 24 | .br 25 | .B " [ --maxconns \fImax-connections\fB ] [ --buffersize \fIbuffer-size\fB ]" 26 | .br 27 | .B " [ --split \fIseconds\fB ] [ --gmtime ] [ --localtime ]" 28 | .br 29 | .B " [ --debug [--debug ...] ]" 30 | 31 | 32 | .SH DESCRIPTION 33 | 34 | .B fstrm_capture 35 | listens on a UNIX domain or TCP socket, receives Frame Streams data, 36 | and writes the data to a file. 37 | 38 | .SH OPTIONS 39 | 40 | .TP 41 | .B -w \fIfilename\fB | --write \fIfilename \fB 42 | Write data to the file \fIfilename\fR. 43 | 44 | If the \fB--gmtime\fR or \fB--localtime\fR option is given, \fIfilename\fR is 45 | preprocessed with \fBstrftime()\fR. 46 | This will allow specifying a format string which includes the date and 47 | time, for example, for the created filename. 48 | 49 | If \fIfilename\fR is "-" and standard output is not connected to a 50 | terminal, \fBfstrm_capture\fR will write to standard output. Output 51 | splitting (\fB-s\fR) may not be used with a \fIfilename\fR of "-". 52 | 53 | Sending \fISIGHUP\fR to \fBfstrm_capture\fR will flush any buffered 54 | output to the file. Sending \fISIGUSR1\fR will close and reopen 55 | the file. 56 | 57 | .TP 58 | .B -t \fIcontent-type\fB | --type \fIcontent-type\fB 59 | Specify the \fIcontent-type\fR to receive from the socket and write 60 | to the output \fIfilename\fR. 61 | 62 | .TP 63 | .B -u \fIsocket-path\fB | --unix \fIsocket-path\fB 64 | Listen on the Unix domain socket \fIsocket-path\fR to receive Frame 65 | Streams data. Only one of \fB-u\fR or \fB-a\fR may be given. 66 | 67 | .TP 68 | .B -a \fIIP\fB | --tcp \fIIP\fB 69 | Listen for TCP connections on address \fIIP\fR to receive Frame Streams 70 | data. Only one of \fB-u\fR or \fB-a\fR may be given. Use of \fB-a\fR 71 | requires a port given with \fB-p\fR. 72 | 73 | .TP 74 | .B -p \fIport\fB | --port \fIport\fB 75 | If \fB-a\fR is given, listen on TCP port \fIport\fR to receive Frame 76 | Streams data. 77 | 78 | .TP 79 | .B -c \fImax-conns\fB | --maxconns \fImax-conns\fB 80 | Allow at most \fImax-conns\fR concurrent connections. If not 81 | specified, concurrent connections are not limited. 82 | 83 | .TP 84 | .B -b \fIbuffersize\fB | --buffersize \fIbuffersize\fB 85 | Set read buffer size to \fIbuffersize\fR bytes. Combined with \fB-c\fR, 86 | this can be used to limit the total memory usage of \fBfstrm_capture\fR. 87 | The \fIbuffersize\fR also affects the maximum frame size which 88 | \fBfstrm_capture\fR will accept. Frames larger than \fIbuffersize\fR, 89 | including the 4-byte framing overhead, will be discarded. 90 | 91 | The default \fIbuffersize\fR is 262144 (256KiB). 92 | 93 | .TP 94 | .B -s \fIinterval\fB | --split \fIinterval\fB 95 | Reopen output file every \fIinterval\fR seconds. Requires the use of 96 | either the \fB--gmtime\fR or \fB--localtime\fR options. 97 | 98 | Note that this file rotation is triggered by incoming data, 99 | so it may be delayed after the interval. 100 | 101 | .TP 102 | .B --gmtime 103 | Process the \fB--write\fR filename through \fBstrftime()\fR with the current 104 | time in GMT. 105 | This \fB--gmtime\fR option may be used to provide a timestamped output 106 | file when starting \fBfstrm_capture\fR or when reopening an output 107 | file using the \fB--split\fR option or when receiving a \fISIGUSR1\fR 108 | signal. 109 | 110 | .TP 111 | .B --localtime 112 | Process the \fB--write\fR filename through \fBstrftime()\fR with the current 113 | time in the system local time zone. 114 | This \fB--localtime\fR option may be used to provide a timestamped output 115 | file when starting \fBfstrm_capture\fR or when reopening an output 116 | file using the \fB--split\fR option or when receiving a \fISIGUSR1\fR 117 | signal. 118 | 119 | 120 | .TP 121 | .B -d [ -d ... ] | --debug [ --debug ] 122 | Increase debugging level. Without \fB-d\fR, \fBfstrm_capture\fR prints only 123 | critical error messages. Up to five \fB-d\fR options may be specified, after 124 | which more repetitions will have no effect. 125 | 126 | .SH EXAMPLES 127 | 128 | Receive dnstap data and save to hourly rotating files 129 | (with a converted filename such as 130 | \fI/var/log/dnstap/dnstap-2018-05-04-12:58:48.fstrm\fR). 131 | 132 | .nf 133 | fstrm_capture -t protobuf:dnstap.Dnstap \\ 134 | -u /var/run/named/dnstap.sock \\ 135 | -w /var/log/dnstap/dnstap-%F-%T.fstrm \\ 136 | -s 3600 --gmtime 137 | .fi 138 | 139 | .SH SEE ALSO 140 | 141 | .BR fstrm_dump (1), 142 | .BR fstrm_replay (1), 143 | .BR strftime (3), 144 | .br 145 | Frame Streams C Library \fBhttps://farsightsec.github.io/fstrm\fR 146 | -------------------------------------------------------------------------------- /man/fstrm_dump.1: -------------------------------------------------------------------------------- 1 | .TH fstrm_dump 1 2 | 3 | .SH NAME 4 | 5 | fstrm_dump \- Display metadata and contents of Frame Streams file. 6 | 7 | .SH SYNOPSIS 8 | 9 | .B fstrm_dump \fIinput-file\fB [\fIoutput-file\fB] 10 | 11 | .SH DESCRIPTION 12 | 13 | .B fstrm_dump 14 | opens 15 | .I input-file 16 | and prints its framing metadata to \fIstderr\fR and frame data to \fIstdout\fR. 17 | The 18 | .I input-file 19 | may be "-" to read Frame Streams data from standard input. 20 | 21 | Frame data is printed as a single line quoted string with non-printable 22 | characters replaced by backslash-prefixed hex escape sequences. For example, 23 | a frame containing "Hello, world\\n" would have its data printed as: 24 | 25 | "Hello, world\\x0a" 26 | 27 | The only framing metadata expected in a Frame Streams file are the 28 | start frame with a content type field, the data frame lengths, and 29 | the stop frame. These are printed, respectively, as: 30 | 31 | FSTRM_CONTROL_START 32 | 33 | FSTRM_CONTROL_FIELD_CONTENT_TYPE (\fIN\fR bytes) 34 | .br 35 | "\fIcontent-type\fR" 36 | 37 | Data frame (\fIN\fR) bytes 38 | 39 | FSTRM_CONTROL_STOP 40 | 41 | If 42 | .B fstrm_dump 43 | is given the second 44 | .I output-file 45 | parameter, input frames are additionally written to 46 | .I output-file. 47 | This is mainly useful for regression testing of the 48 | .I fstrm_file_writer 49 | code. 50 | 51 | .SH SEE ALSO 52 | 53 | .BR fstrm_capture (1), 54 | .BR fstrm_replay (1), 55 | .br 56 | Frame Streams C Library \fBhttps://farsightsec.github.io/fstrm\fR 57 | -------------------------------------------------------------------------------- /man/fstrm_replay.1: -------------------------------------------------------------------------------- 1 | .TH fstrm_replay 1 2 | 3 | .SH NAME 4 | 5 | fstrm_replay \- Replay saved Frame Streams data to a socket connection. 6 | 7 | .SH SYNOPSIS 8 | 9 | .B fstrm_replay -t \fIcontent-type\fB -r \fIfile\fB [ -r \fIfile\fB ... ] 10 | .br 11 | .B " [ -u \fIsocket-path\fB ] [ -a \fIIP\fB -p \fIport\fB ]" 12 | 13 | .PP 14 | 15 | .B fstrm_replay --type \fIcontent-type\fB 16 | .br 17 | .B " --read \fIfile\fB [ --read \fIfile\fB ... ] 18 | .br 19 | .B " [ --unix \fIsocket-path\fB ] [ --tcp \fIIP\fB --port \fIport\fB ]" 20 | 21 | .SH DESCRIPTION 22 | 23 | .B fstrm_replay 24 | connects to a Frame Streams receiver on either the given UNIX domain 25 | \fIsocket-path\fR or TCP \fIaddress\fR and \fIport\fR, then reads 26 | and sends data of the supplied \fIcontent-type\fR from the given 27 | \fIfile(s)\fR. 28 | 29 | .SH OPTIONS 30 | 31 | .TP 32 | .B -t \fIcontent-type\fB | --type \fIcontent-type\fB 33 | Specify the \fIcontent-type\fR to read from files and send to the 34 | Frame Streams socket. Files whose content-type differ are skipped. 35 | If the socket server does not accept the \fIcontent-type\fR, 36 | .B fstrm_replay 37 | will fail. 38 | 39 | .TP 40 | .B -r \fIfile\fB | --read \fIfile\fB 41 | Read data from \fIfile\fR. Multiple files can be given with multiple 42 | \fB-r\fR options. Files which cannot be opened, or do not contain valid 43 | Frame Streams data will be skipped. 44 | 45 | .TP 46 | .B -u \fIsocket-path\fB | --unix \fIsocket-path\fR 47 | Connect to Unix domain \fIsocket-path\fR to write Frame Streams data. 48 | Only one of \fB-u\fR or \fB-a\fR may be given. 49 | 50 | .TP 51 | .B -a \fIIP\fB | --tcp \fIIP\fB 52 | Connect to TCP address \fIIP\fR to write Frame Streams data. Only one of 53 | \fB-u\fR or \fB-a\fR may be given. Use of \fB-a\fR requires a port 54 | given with \fB-p\fR. 55 | 56 | .TP 57 | .B -p \fIport\fB | --port \fIport\fB 58 | If \fB-a\fR is given, use TCP port \fIport\fR to write Frame Streams 59 | data. 60 | 61 | .SH EXAMPLES 62 | 63 | Replay dnstap data over UNIX domain socket: 64 | 65 | .nf 66 | fstrm_replay -t protobuf:dnstap.Dnstap \\ 67 | -u /var/run/named/dnstap.sock -r dnstap-log.fstrm 68 | .fi 69 | 70 | .SH SEE ALSO 71 | 72 | .BR fstrm_capture (1), 73 | .BR fstrm_dump (1), 74 | .br 75 | Frame Streams C Library \fBhttps://farsightsec.github.io/fstrm\fR 76 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | fstrm_capture 2 | fstrm_dump 3 | fstrm_replay 4 | -------------------------------------------------------------------------------- /src/fstrm_dump.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, 2018 by Farsight Security, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | #include "libmy/print_string.h" 32 | 33 | static fstrm_res 34 | process_start_frame(struct fstrm_reader *r, struct fstrm_writer_options *wopt) 35 | { 36 | fstrm_res res; 37 | const struct fstrm_control *control = NULL; 38 | size_t n_content_type = 0; 39 | const uint8_t *content_type = NULL; 40 | size_t len_content_type = 0; 41 | 42 | res = fstrm_reader_get_control(r, FSTRM_CONTROL_START, &control); 43 | if (res != fstrm_res_success) 44 | return res; 45 | fputs("FSTRM_CONTROL_START.\n", stderr); 46 | 47 | res = fstrm_control_get_num_field_content_type(control, &n_content_type); 48 | if (res != fstrm_res_success) 49 | return res; 50 | if (n_content_type > 0) { 51 | res = fstrm_control_get_field_content_type(control, 0, 52 | &content_type, &len_content_type); 53 | if (res != fstrm_res_success) 54 | return res; 55 | fprintf(stderr, "FSTRM_CONTROL_FIELD_CONTENT_TYPE (%zd bytes).\n ", 56 | len_content_type); 57 | print_string(content_type, len_content_type, stderr); 58 | fputc('\n', stderr); 59 | } 60 | 61 | if (wopt != NULL && content_type != NULL) { 62 | res = fstrm_writer_options_add_content_type(wopt, 63 | content_type, len_content_type); 64 | if (res != fstrm_res_success) 65 | return res; 66 | } 67 | 68 | return fstrm_res_success; 69 | } 70 | 71 | static fstrm_res 72 | print_stop_frame(struct fstrm_reader *r) 73 | { 74 | fstrm_res res; 75 | const struct fstrm_control *control = NULL; 76 | 77 | res = fstrm_reader_get_control(r, FSTRM_CONTROL_STOP, &control); 78 | if (res != fstrm_res_success) 79 | return res; 80 | fputs("FSTRM_CONTROL_STOP.\n", stderr); 81 | 82 | return fstrm_res_success; 83 | } 84 | 85 | static fstrm_res 86 | print_data_frame(const uint8_t *data, size_t len_data) 87 | { 88 | fprintf(stderr, "Data frame (%zd) bytes.\n", len_data); 89 | putchar(' '); 90 | print_string(data, len_data, stdout); 91 | putchar('\n'); 92 | return fstrm_res_success; 93 | } 94 | 95 | int main(int argc, char **argv) 96 | { 97 | const char *input_fname = NULL; 98 | const char *output_fname = NULL; 99 | 100 | fstrm_res res = fstrm_res_failure; 101 | struct fstrm_file_options *fopt = NULL; 102 | struct fstrm_writer_options *wopt = NULL; 103 | struct fstrm_reader *r = NULL; 104 | struct fstrm_writer *w = NULL; 105 | 106 | int rv = EXIT_FAILURE; 107 | 108 | /* Args. */ 109 | if (argc != 2 && argc != 3) { 110 | fprintf(stderr, "Usage: %s []\n", argv[0]); 111 | fprintf(stderr, "Dumps a Frame Streams formatted input file.\n\n"); 112 | return EXIT_FAILURE; 113 | } 114 | input_fname = argv[1]; 115 | if (argc == 3) 116 | output_fname = argv[2]; 117 | 118 | /* Line buffering. */ 119 | setvbuf(stdout, NULL, _IOLBF, 0); 120 | setvbuf(stderr, NULL, _IOLBF, 0); 121 | 122 | /* Setup file reader options. */ 123 | fopt = fstrm_file_options_init(); 124 | fstrm_file_options_set_file_path(fopt, input_fname); 125 | 126 | /* Initialize file reader. */ 127 | r = fstrm_file_reader_init(fopt, NULL); 128 | if (r == NULL) { 129 | fputs("Error: fstrm_file_reader_init() failed.\n", stderr); 130 | goto out; 131 | } 132 | res = fstrm_reader_open(r); 133 | if (res != fstrm_res_success) { 134 | fputs("Error: fstrm_reader_open() failed.\n", stderr); 135 | goto out; 136 | } 137 | 138 | if (output_fname != NULL) { 139 | /* Setup file writer options. */ 140 | fstrm_file_options_set_file_path(fopt, output_fname); 141 | 142 | /* Setup writer options. */ 143 | wopt = fstrm_writer_options_init(); 144 | 145 | /* Copy "content type" from the reader's START frame. */ 146 | res = process_start_frame(r, wopt); 147 | if (res != fstrm_res_success) { 148 | fputs("Error: process_start_frame() failed.\n", stderr); 149 | goto out; 150 | } 151 | 152 | /* Initialize file writer. */ 153 | w = fstrm_file_writer_init(fopt, wopt); 154 | if (w == NULL) { 155 | fputs("Error: fstrm_file_writer_init() failed.\n", stderr); 156 | goto out; 157 | } 158 | res = fstrm_writer_open(w); 159 | if (res != fstrm_res_success) { 160 | fstrm_writer_destroy(&w); 161 | fputs("Error: fstrm_writer_open() failed.\n", stderr); 162 | goto out; 163 | } 164 | } else { 165 | /* Process the START frame. */ 166 | res = process_start_frame(r, NULL); 167 | if (res != fstrm_res_success) { 168 | fprintf(stderr, "Error: process_start_frame() failed.\n"); 169 | goto out; 170 | } 171 | } 172 | 173 | /* Loop over data frames. */ 174 | for (;;) { 175 | const uint8_t *data; 176 | size_t len_data; 177 | 178 | res = fstrm_reader_read(r, &data, &len_data); 179 | if (res == fstrm_res_success) { 180 | /* Got a data frame. */ 181 | res = print_data_frame(data, len_data); 182 | if (res != fstrm_res_success) { 183 | fprintf(stderr, "Error: print_data_frame() failed.\n"); 184 | goto out; 185 | } 186 | if (w != NULL) { 187 | /* Write the data frame. */ 188 | res = fstrm_writer_write(w, data, len_data); 189 | if (res != fstrm_res_success) { 190 | fprintf(stderr, "Error: write_data_frame() failed.\n"); 191 | goto out; 192 | } 193 | } 194 | } else if (res == fstrm_res_stop) { 195 | /* Normal end of data stream. */ 196 | res = print_stop_frame(r); 197 | if (res != fstrm_res_success) { 198 | fprintf(stderr, "Error: unable to read STOP frame.\n"); 199 | goto out; 200 | } 201 | rv = EXIT_SUCCESS; 202 | break; 203 | } else { 204 | /* Abnormal end. */ 205 | fprintf(stderr, "Error: fstrm_reader_read() failed.\n"); 206 | goto out; 207 | } 208 | } 209 | 210 | out: 211 | /* Cleanup options. */ 212 | fstrm_file_options_destroy(&fopt); 213 | fstrm_writer_options_destroy(&wopt); 214 | 215 | /* Cleanup reader. */ 216 | fstrm_reader_destroy(&r); 217 | 218 | /* Cleanup writer. */ 219 | if (w != NULL) { 220 | res = fstrm_writer_close(w); 221 | if (res != fstrm_res_success) { 222 | fprintf(stderr, "Error: fstrm_writer_close() failed.\n"); 223 | rv = EXIT_FAILURE; 224 | } 225 | fstrm_writer_destroy(&w); 226 | } 227 | 228 | return rv; 229 | } 230 | -------------------------------------------------------------------------------- /src/fstrm_replay.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Farsight Security, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | 36 | #include "libmy/argv.h" 37 | 38 | struct replay { 39 | struct replay_args *args; 40 | uint8_t *content_type; 41 | size_t len_content_type; 42 | }; 43 | 44 | struct replay_args { 45 | bool help; 46 | char *content_type; 47 | char *unix_address; 48 | char *tcp_address; 49 | char *tcp_port; 50 | argv_array_t files; 51 | }; 52 | 53 | static struct replay g_program_ctx; 54 | static struct replay_args g_program_args; 55 | 56 | static argv_t g_args[] = { 57 | { 'h', "help", 58 | ARGV_BOOL, 59 | &g_program_args.help, 60 | NULL, 61 | "display this help text and exit" }, 62 | 63 | { 't', "type", 64 | ARGV_CHAR_P | ARGV_FLAG_MAND, 65 | &g_program_args.content_type, 66 | "", 67 | "Frame Streams content type" }, 68 | 69 | { 'u', "unix", 70 | ARGV_CHAR_P, 71 | &g_program_args.unix_address, 72 | "", 73 | "Unix socket path to write to" }, 74 | 75 | /* ARGV_ONE_OF indicates that the user must specify the 76 | * previous option (-u) or next option (-a), but not both. 77 | */ 78 | { ARGV_ONE_OF, 0, 0, 0, 0, 0 }, 79 | 80 | { 'a', "tcp", 81 | ARGV_CHAR_P, 82 | &g_program_args.tcp_address, 83 | "
", 84 | "TCP socket address to write to" }, 85 | 86 | { 'p', "port", 87 | ARGV_CHAR_P, 88 | &g_program_args.tcp_port, 89 | "", 90 | "TCP socket port to write to" }, 91 | 92 | { 'r', "read-file", 93 | ARGV_CHAR_P | ARGV_FLAG_ARRAY | ARGV_FLAG_MAND, 94 | &g_program_args.files, 95 | "", 96 | "Files to read Frame Streams data from" }, 97 | 98 | { ARGV_LAST, 0, 0, 0, 0, 0 }, 99 | }; 100 | 101 | static void 102 | usage(const char *msg) 103 | { 104 | if(msg) 105 | fprintf(stderr, "%s: Usage error: %s\n", argv_program, msg); 106 | argv_usage(g_args, ARGV_USAGE_DEFAULT); 107 | argv_cleanup(g_args); 108 | exit(EXIT_FAILURE); 109 | } 110 | 111 | static bool 112 | parse_args(int argc, char **argv, struct replay *ctx) 113 | { 114 | if (argv_process(g_args, argc, argv) != 0) 115 | return false; 116 | 117 | if (g_program_args.help) 118 | return false; 119 | 120 | if ((g_program_args.tcp_address != NULL) && 121 | (g_program_args.tcp_port == NULL)) 122 | usage("--tcp requires --port"); 123 | 124 | ctx->content_type = (uint8_t *)g_program_args.content_type; 125 | ctx->len_content_type = strlen(g_program_args.content_type); 126 | return true; 127 | } 128 | 129 | static struct fstrm_writer * 130 | init_writer(void) 131 | { 132 | struct fstrm_writer *w; 133 | struct fstrm_writer_options *wopt; 134 | fstrm_res res; 135 | 136 | /* Setup writer options. */ 137 | wopt = fstrm_writer_options_init(); 138 | res = fstrm_writer_options_add_content_type(wopt, 139 | g_program_ctx.content_type, 140 | g_program_ctx.len_content_type); 141 | if (res != fstrm_res_success) { 142 | fstrm_writer_options_destroy(&wopt); 143 | return NULL; 144 | } 145 | 146 | if (g_program_args.unix_address != NULL) { 147 | struct fstrm_unix_writer_options *uwopt; 148 | 149 | if (g_program_args.tcp_port != NULL) 150 | fputs("Warning: Ignoring --port with --unix.\n", stderr); 151 | 152 | uwopt = fstrm_unix_writer_options_init(); 153 | fstrm_unix_writer_options_set_socket_path(uwopt, g_program_args.unix_address); 154 | w = fstrm_unix_writer_init(uwopt, wopt); 155 | fstrm_unix_writer_options_destroy(&uwopt); 156 | fstrm_writer_options_destroy(&wopt); 157 | if (w == NULL) { 158 | fputs("Error: fstrm_unix_writer_init() failed.\n", stderr); 159 | return NULL; 160 | } 161 | } else { 162 | struct fstrm_tcp_writer_options *twopt; 163 | unsigned long port; 164 | char *endptr; 165 | struct sockaddr_in sin; 166 | struct sockaddr_in6 sin6; 167 | 168 | /* Parse TCP listen port. */ 169 | port = strtoul(g_program_args.tcp_port, &endptr, 0); 170 | if (*endptr != '\0' || port > UINT16_MAX) 171 | usage("Failed to parse TCP listen port"); 172 | 173 | /* Parse TCP listen address. */ 174 | if ((inet_pton(AF_INET, g_program_args.tcp_address, &sin) != 1) && 175 | (inet_pton(AF_INET6, g_program_args.tcp_address, &sin6) != 1)) 176 | usage("Failed to parse TCP listen address"); 177 | 178 | twopt = fstrm_tcp_writer_options_init(); 179 | fstrm_tcp_writer_options_set_socket_address(twopt, g_program_args.tcp_address); 180 | fstrm_tcp_writer_options_set_socket_port(twopt, g_program_args.tcp_port); 181 | 182 | w = fstrm_tcp_writer_init(twopt, wopt); 183 | fstrm_tcp_writer_options_destroy(&twopt); 184 | fstrm_writer_options_destroy(&wopt); 185 | 186 | if (w == NULL) { 187 | fputs("Error: fstrm_tcp_writer_init() failed.\n", stderr); 188 | return NULL; 189 | } 190 | } 191 | 192 | res = fstrm_writer_open(w); 193 | if (res != fstrm_res_success) { 194 | fstrm_writer_destroy(&w); 195 | fputs("Error: fstrm_writer_open() failed.\n", stderr); 196 | return NULL; 197 | } 198 | 199 | return w; 200 | } 201 | 202 | static void 203 | process_file(const char *fname, struct fstrm_writer *w) 204 | { 205 | struct fstrm_reader *r = NULL; 206 | struct fstrm_file_options *fopt = NULL; 207 | const struct fstrm_control *control = NULL; 208 | fstrm_res res; 209 | 210 | fopt = fstrm_file_options_init(); 211 | fstrm_file_options_set_file_path(fopt, fname); 212 | 213 | /* Initialize file reader. */ 214 | r = fstrm_file_reader_init(fopt, NULL); 215 | fstrm_file_options_destroy(&fopt); 216 | if (r == NULL) { 217 | fprintf(stderr, "Warning: failed to open %s, skipping\n", fname); 218 | return; 219 | } 220 | 221 | /* Check file content type. */ 222 | res = fstrm_reader_get_control(r, FSTRM_CONTROL_START, &control); 223 | if (res != fstrm_res_success) { 224 | fprintf(stderr, "Warning: failed to read control frame from %s, skipping\n", fname); 225 | fstrm_reader_destroy(&r); 226 | return; 227 | } 228 | 229 | res = fstrm_control_match_field_content_type(control, 230 | g_program_ctx.content_type, 231 | g_program_ctx.len_content_type); 232 | if (res != fstrm_res_success) { 233 | fprintf(stderr, "Warning: content type mismatch for %s, skipping\n", fname); 234 | fstrm_reader_destroy(&r); 235 | return; 236 | } 237 | 238 | /* Loop over file data. */ 239 | for (;;) { 240 | const uint8_t *data; 241 | size_t len_data; 242 | 243 | res = fstrm_reader_read(r, &data, &len_data); 244 | if (res == fstrm_res_success) { 245 | /* Write the data frame. */ 246 | res = fstrm_writer_write(w, data, len_data); 247 | if (res != fstrm_res_success) { 248 | fputs("Error: write_data_frame() failed", stderr); 249 | exit(EXIT_FAILURE); 250 | } 251 | } else if (res == fstrm_res_stop) { 252 | /* Normal end of data stream. */ 253 | res = fstrm_reader_get_control(r, FSTRM_CONTROL_STOP, &control); 254 | if (res != fstrm_res_success) { 255 | fprintf(stderr, "Error: unable to read STOP frame from %s.\n", fname); 256 | } 257 | break; 258 | } else { 259 | /* Abnormal end. */ 260 | fprintf(stderr, "Error: fstrm_reader_read() failed.\n"); 261 | break; 262 | } 263 | } 264 | fstrm_reader_destroy(&r); 265 | } 266 | 267 | int main(int argc, char **argv) 268 | { 269 | int i; 270 | fstrm_res res; 271 | struct fstrm_writer *w = NULL; 272 | 273 | if (!parse_args(argc, argv, &g_program_ctx)) 274 | usage(NULL); 275 | 276 | w = init_writer(); 277 | if (w == NULL) 278 | exit(EXIT_FAILURE); 279 | 280 | for (i = 0; i < ARGV_ARRAY_COUNT(g_program_args.files); i++) { 281 | const char *in_fname; 282 | in_fname = ARGV_ARRAY_ENTRY(g_program_args.files, char *, i); 283 | process_file(in_fname, w); 284 | } 285 | 286 | res = fstrm_writer_close(w); 287 | if (res != fstrm_res_success) 288 | fputs("Error: fstrm_writer_close() failed", stderr); 289 | 290 | fstrm_writer_destroy(&w); 291 | return 0; 292 | } 293 | -------------------------------------------------------------------------------- /t/.gitignore: -------------------------------------------------------------------------------- 1 | test_control 2 | test_file_hello 3 | test_fstrm_io_file 4 | test_fstrm_io_sock 5 | test_queue 6 | test_writer_hello 7 | program_tests/test_fstrm_dump.sh 8 | program_tests/test_fstrm_replay.sh 9 | -------------------------------------------------------------------------------- /t/program_tests/test-fstrm.txt: -------------------------------------------------------------------------------- 1 | FSTRM_CONTROL_START. 2 | FSTRM_CONTROL_FIELD_CONTENT_TYPE (10 bytes). 3 | "test:hello" 4 | Data frame (16) bytes. 5 | "Hello, world #0\x0a" 6 | Data frame (16) bytes. 7 | "Hello, world #1\x0a" 8 | Data frame (16) bytes. 9 | "Hello, world #2\x0a" 10 | Data frame (16) bytes. 11 | "Hello, world #3\x0a" 12 | Data frame (16) bytes. 13 | "Hello, world #4\x0a" 14 | Data frame (16) bytes. 15 | "Hello, world #5\x0a" 16 | Data frame (16) bytes. 17 | "Hello, world #6\x0a" 18 | Data frame (16) bytes. 19 | "Hello, world #7\x0a" 20 | Data frame (16) bytes. 21 | "Hello, world #8\x0a" 22 | Data frame (16) bytes. 23 | "Hello, world #9\x0a" 24 | FSTRM_CONTROL_STOP. 25 | -------------------------------------------------------------------------------- /t/program_tests/test.fstrm: -------------------------------------------------------------------------------- 1 |  2 | test:helloHello, world #0 3 | Hello, world #1 4 | Hello, world #2 5 | Hello, world #3 6 | Hello, world #4 7 | Hello, world #5 8 | Hello, world #6 9 | Hello, world #7 10 | Hello, world #8 11 | Hello, world #9 12 |  -------------------------------------------------------------------------------- /t/program_tests/test_fstrm_dump.sh.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | exedir="@abs_top_builddir@/src" 4 | testdir="@abs_top_srcdir@/t/program_tests" 5 | 6 | input="${testdir}/test.fstrm" 7 | input_txt="${testdir}/test-fstrm.txt" 8 | 9 | rc=0 10 | 11 | test="fstrm_dump display" 12 | if $exedir/fstrm_dump $input 2>&1 | cmp - $input_txt; then 13 | echo $test: PASS 14 | else 15 | echo $test: FAIL 16 | rc=1 17 | fi 18 | 19 | output=$(mktemp) 20 | 21 | test="fstrm_dump copy" 22 | $exedir/fstrm_dump $input $output >/dev/null 2>&1 23 | if $exedir/fstrm_dump $output 2>&1 | cmp - $input_txt; then 24 | echo $test: PASS 25 | else 26 | echo $test: FAIL 27 | rc=1 28 | fi 29 | 30 | rm -f $output 31 | exit $rc 32 | -------------------------------------------------------------------------------- /t/program_tests/test_fstrm_replay.sh.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | exedir="@abs_top_builddir@/src" 4 | testdir="@abs_top_srcdir@/t/program_tests" 5 | 6 | input="${testdir}/test.fstrm" 7 | input_txt="${testdir}/test-fstrm.txt" 8 | 9 | rc=0 10 | 11 | output=$(mktemp) 12 | sockpath=$(mktemp) 13 | 14 | test="fstrm_replay unix socket" 15 | args="-t test:hello -u $sockpath" 16 | $exedir/fstrm_capture -w $output $args & 17 | cappid=$! 18 | sleep 1 19 | 20 | if $exedir/fstrm_replay -r $input $args; then 21 | kill $cappid 22 | wait $cappid 23 | if cmp $input $output; then 24 | echo $test: PASS 25 | else 26 | echo $test: FAIL "(capture differs)" 27 | rc=1 28 | fi 29 | else 30 | kill $cappid 31 | echo $test: FAIL "(replay failed)" 32 | rc=1 33 | fi 34 | 35 | rm -f $output 36 | output=$(mktemp) 37 | 38 | test="fstrm_replay tcp socket" 39 | args="-a 127.0.0.1 -p 15532 -t test:hello" 40 | $exedir/fstrm_capture -w $output $args & 41 | cappid=$! 42 | sleep 1 43 | 44 | if $exedir/fstrm_replay -r $input $args; then 45 | kill $cappid 46 | wait $cappid 47 | if cmp $input $output; then 48 | echo $test: PASS 49 | else 50 | echo $test: FAIL "(capture differs)" 51 | rc=1 52 | fi 53 | else 54 | kill $cappid 55 | echo $test: FAIL "(replay failed)" 56 | rc=1 57 | fi 58 | 59 | rm -f $output 60 | 61 | exit $rc 62 | -------------------------------------------------------------------------------- /t/run_test_fstrm_io_file.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | TNAME="test_fstrm_io_file" 4 | FILENAME="./test.fstrm" 5 | 6 | if [ -z "$DIRNAME" ]; then 7 | DIRNAME="$(dirname $(readlink -f $0))" 8 | fi 9 | 10 | for QUEUE_MODEL in SPSC MPSC; do 11 | for NUM_THREADS in 1 4 16; do 12 | for NUM_MESSAGES in 1 1000 100000; do 13 | $DIRNAME/$TNAME "$FILENAME" $QUEUE_MODEL $NUM_THREADS $NUM_MESSAGES 14 | done 15 | done 16 | done 17 | 18 | rm -f "$FILENAME" 19 | -------------------------------------------------------------------------------- /t/run_test_fstrm_io_tcp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | TNAME="test_fstrm_io_sock tcp" 4 | SOCKADDR="127.0.0.1" 5 | 6 | if [ -z "$DIRNAME" ]; then 7 | DIRNAME="$(dirname $(readlink -f $0))" 8 | fi 9 | 10 | for QUEUE_MODEL in SPSC MPSC; do 11 | for NUM_THREADS in 1 4 16; do 12 | for NUM_MESSAGES in 1 1000 100000; do 13 | $DIRNAME/$TNAME $SOCKADDR $QUEUE_MODEL $NUM_THREADS $NUM_MESSAGES 14 | done 15 | done 16 | done 17 | -------------------------------------------------------------------------------- /t/run_test_fstrm_io_unix.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | TNAME="test_fstrm_io_sock unix" 4 | SOCKNAME="./test.sock" 5 | 6 | if [ -z "$DIRNAME" ]; then 7 | DIRNAME="$(dirname $(readlink -f $0))" 8 | fi 9 | 10 | for QUEUE_MODEL in SPSC MPSC; do 11 | for NUM_THREADS in 1 4 16; do 12 | for NUM_MESSAGES in 1 1000 100000; do 13 | $DIRNAME/$TNAME "$SOCKNAME" $QUEUE_MODEL $NUM_THREADS $NUM_MESSAGES 14 | done 15 | done 16 | done 17 | 18 | rm -f "$SOCKNAME" 19 | -------------------------------------------------------------------------------- /t/run_test_queue.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | TNAME="test_queue" 4 | 5 | if [ -z "$DIRNAME" ]; then 6 | DIRNAME="$(dirname $(readlink -f $0))" 7 | fi 8 | 9 | if [ -z "$QSIZE" ]; then 10 | QSIZE=128 11 | fi 12 | 13 | if [ -z "$QSECONDS" ]; then 14 | QSECONDS=1 15 | fi 16 | 17 | $DIRNAME/$TNAME spin "$QSIZE" "$QSECONDS" 18 | echo 19 | $DIRNAME/$TNAME slow_producer "$QSIZE" "$QSECONDS" 20 | echo 21 | $DIRNAME/$TNAME slow_consumer "$QSIZE" "$QSECONDS" 22 | echo 23 | -------------------------------------------------------------------------------- /t/test_file_hello.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 by Farsight Security, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | /** 26 | * test_file_hello: simple "hello world" fstrm_file test. 27 | * 28 | * Writes several messages to a test file, then reads the test file and 29 | * verifies the contents of the test messages. 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include 40 | 41 | static const char *test_pattern = "Hello world #%d"; 42 | static const char *test_content_type = "test:hello"; 43 | static const int num_iterations = 1000; 44 | 45 | static fstrm_res 46 | write_message(struct fstrm_writer *w, int i) 47 | { 48 | fstrm_res res; 49 | char buf[100] = {0}; 50 | 51 | sprintf(buf, test_pattern, i); 52 | res = fstrm_writer_write(w, buf, strlen(buf) + 1); 53 | if (res != fstrm_res_success) { 54 | printf("%s: fstrm_writer_write() failed.\n", __func__); 55 | return res; 56 | } 57 | 58 | return fstrm_res_success; 59 | } 60 | 61 | static fstrm_res 62 | read_message(struct fstrm_reader *r, int i) 63 | { 64 | fstrm_res res; 65 | char buf[100] = {0}; 66 | const uint8_t *rbuf = NULL; 67 | size_t len_rbuf = 0; 68 | 69 | sprintf(buf, test_pattern, i); 70 | res = fstrm_reader_read(r, &rbuf, &len_rbuf); 71 | if (res != fstrm_res_success) { 72 | printf("%s: fstrm_reader_read() failed.\n", __func__); 73 | return res; 74 | } 75 | 76 | if (len_rbuf != strlen(buf) + 1) { 77 | printf("%s: string length comparison failed.\n", __func__); 78 | return fstrm_res_failure; 79 | } 80 | 81 | if (memcmp(buf, rbuf, len_rbuf) != 0) { 82 | printf("%s: string data comparison failed.\n", __func__); 83 | return fstrm_res_failure; 84 | } 85 | 86 | return fstrm_res_success; 87 | } 88 | 89 | int 90 | main(void) 91 | { 92 | int rv = 0; 93 | fstrm_res res = fstrm_res_failure; 94 | struct fstrm_file_options *fopt = NULL; 95 | struct fstrm_reader *r = NULL; 96 | struct fstrm_writer *w = NULL; 97 | struct fstrm_reader_options *ropt = NULL; 98 | struct fstrm_writer_options *wopt = NULL; 99 | 100 | /* Generate temporary filename. */ 101 | char file_path[] = "./test.fstrm.XXXXXX"; 102 | rv = mkstemp(file_path); 103 | if (rv < 0) { 104 | printf("Error: mkstemp() failed: %s\n", strerror(errno)); 105 | return EXIT_FAILURE; 106 | } 107 | 108 | /* File options. */ 109 | fopt = fstrm_file_options_init(); 110 | fstrm_file_options_set_file_path(fopt, file_path); 111 | 112 | /* Writer options. */ 113 | wopt = fstrm_writer_options_init(); 114 | res = fstrm_writer_options_add_content_type(wopt, 115 | test_content_type, strlen(test_content_type)); 116 | if (res != fstrm_res_success) { 117 | printf("Error: fstrm_writer_options_add_content_type() failed.\n"); 118 | goto fail; 119 | } 120 | 121 | /* Open writer. */ 122 | printf("Opening file %s for writing.\n", file_path); 123 | w = fstrm_file_writer_init(fopt, wopt); 124 | if (!w) { 125 | printf("Error: fstrm_file_writer_init() failed.\n"); 126 | goto fail; 127 | } 128 | res = fstrm_writer_open(w); 129 | if (res != fstrm_res_success) { 130 | printf("Error: fstrm_writer_open() failed.\n"); 131 | goto fail; 132 | } 133 | 134 | /* Double open. */ 135 | printf("Doing a double open.\n"); 136 | res = fstrm_writer_open(w); 137 | if (res != fstrm_res_success) { 138 | printf("Error: fstrm_writer_open() failed.\n"); 139 | goto fail; 140 | } 141 | 142 | /* Write hello messages. */ 143 | for (int i = 0; i < num_iterations; i++) { 144 | res = write_message(w, i); 145 | if (res != fstrm_res_success) { 146 | printf("Error: write_message() failed.\n"); 147 | goto fail; 148 | } 149 | } 150 | printf("Wrote %d messages.\n", num_iterations); 151 | 152 | /* Close writer. */ 153 | res = fstrm_writer_destroy(&w); 154 | if (res != fstrm_res_success) { 155 | printf("Error: fstrm_writer_destroy() failed.\n"); 156 | goto fail; 157 | } 158 | 159 | /* Reader options. */ 160 | ropt = fstrm_reader_options_init(); 161 | res = fstrm_reader_options_add_content_type(ropt, 162 | test_content_type, strlen(test_content_type)); 163 | if (res != fstrm_res_success) { 164 | printf("Error: fstrm_reader_options_add_content_type() failed.\n"); 165 | goto fail; 166 | } 167 | 168 | /* Open reader. */ 169 | printf("Opening file %s for reading.\n", file_path); 170 | r = fstrm_file_reader_init(fopt, ropt); 171 | if (!r) { 172 | printf("Error: fstrm_file_reader_init() failed.\n"); 173 | goto fail; 174 | } 175 | res = fstrm_reader_open(r); 176 | if (res != fstrm_res_success) { 177 | printf("Error: fstrm_reader_open() failed.\n"); 178 | goto fail; 179 | } 180 | 181 | /* Read hello messages. */ 182 | for (int i = 0; i < num_iterations; i++) { 183 | res = read_message(r, i); 184 | if (res != fstrm_res_success) { 185 | printf("Error: read_message() failed.\n"); 186 | goto fail; 187 | } 188 | } 189 | printf("Read %d messages.\n", num_iterations); 190 | 191 | /* 192 | * The next read should fail with fstrm_res_stop, since we read exactly 193 | * the number of messages in the file. 194 | */ 195 | const uint8_t *data = NULL; 196 | size_t len_data = 0; 197 | res = fstrm_reader_read(r, &data, &len_data); 198 | if (res != fstrm_res_stop) { 199 | printf("Error: got unexpected result from fstrm_reader_read(): %d.\n", res); 200 | res = fstrm_res_failure; 201 | goto fail; 202 | } 203 | 204 | /* Close reader. */ 205 | (void)fstrm_reader_destroy(&r); 206 | 207 | res = fstrm_res_success; 208 | fail: 209 | /* Cleanup. */ 210 | printf("Unlinking file %s.\n", file_path); 211 | (void)unlink(file_path); 212 | 213 | fstrm_file_options_destroy(&fopt); 214 | (void)fstrm_reader_destroy(&r); 215 | (void)fstrm_writer_destroy(&w); 216 | fstrm_reader_options_destroy(&ropt); 217 | fstrm_writer_options_destroy(&wopt); 218 | 219 | if (res == fstrm_res_success) 220 | return EXIT_SUCCESS; 221 | return EXIT_FAILURE; 222 | } 223 | -------------------------------------------------------------------------------- /t/test_writer_hello.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 by Farsight Security, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | /** 26 | * test_writer_hello: simple "hello world" fstrm_io test. 27 | * 28 | * Instantiates a dummy writer implementation which captures all writes, then 29 | * verifies that the correct byte stream sequence was generated by the library. 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | 40 | #include "libmy/my_alloc.h" 41 | #include "libmy/print_string.h" 42 | 43 | static const char *test_content_type = "test:hello"; 44 | static const int num_iterations = 1000; 45 | 46 | struct test_buf { 47 | struct test_buf *next; 48 | size_t len; 49 | void *data; 50 | }; 51 | 52 | static struct test_buf t_head; 53 | static struct test_buf *t_cur = &t_head; 54 | 55 | static struct test_buf h_head; 56 | static struct test_buf *h_cur = &h_head; 57 | 58 | static int num_control_frames = 0; 59 | static int num_iovecs = 0; 60 | 61 | static fstrm_res 62 | test_rdwr_destroy(__attribute__((unused)) void *obj) 63 | { 64 | fprintf(stderr, "%s: called\n", __func__); 65 | return fstrm_res_success; 66 | } 67 | 68 | static fstrm_res 69 | test_rdwr_open(__attribute__((unused)) void *obj) 70 | { 71 | fprintf(stderr, "%s: called\n", __func__); 72 | return fstrm_res_success; 73 | } 74 | 75 | static fstrm_res 76 | test_rdwr_close(__attribute__((unused)) void *obj) 77 | { 78 | fprintf(stderr, "%s: called\n", __func__); 79 | return fstrm_res_success; 80 | } 81 | 82 | static fstrm_res 83 | test_rdwr_write(__attribute__((unused)) void *obj, 84 | const struct iovec *iov, int iovcnt) 85 | { 86 | size_t nbytes = 0; 87 | 88 | fprintf(stderr, "%s: called, iov= %p, iovcnt= %d\n", 89 | __func__, (void *) iov, iovcnt); 90 | 91 | assert(iovcnt > 0); 92 | 93 | assert(iov[0].iov_len >= 4); 94 | if (memcmp(iov[0].iov_base, "\x00\x00\x00\x00", 4) == 0) { 95 | fprintf(stderr, "%s: got a control frame (%zd bytes): ", 96 | __func__, iov[0].iov_len); 97 | print_string(iov[0].iov_base, iov[0].iov_len, stderr); 98 | fputc('\n', stderr); 99 | num_control_frames++; 100 | return fstrm_res_success; 101 | } 102 | 103 | for (int i = 0; i < iovcnt; i++) { 104 | t_cur->next = my_calloc(1, sizeof(struct test_buf)); 105 | t_cur = t_cur->next; 106 | t_cur->len = iov[i].iov_len; 107 | t_cur->data = my_calloc(1, t_cur->len); 108 | memmove(t_cur->data, iov[i].iov_base, iov[i].iov_len); 109 | nbytes += iov[i].iov_len; 110 | } 111 | num_iovecs += iovcnt; 112 | 113 | fprintf(stderr, "%s: got %zd bytes\n", __func__, nbytes); 114 | return fstrm_res_success; 115 | } 116 | 117 | static int 118 | do_checks(void) 119 | { 120 | struct test_buf *h, *h_next; 121 | struct test_buf *t, *t_next; 122 | 123 | h = h_head.next; 124 | t = t_head.next; 125 | if (!h || !t) 126 | return EXIT_FAILURE; 127 | 128 | if (num_iovecs != 2*num_iterations) { 129 | fprintf(stderr, "%s: didn't get the right number of iovec's\n", __func__); 130 | fprintf(stderr, "%s: num_iovecs= %d, num_iterations= %d\n", 131 | __func__, num_iovecs, num_iterations); 132 | return EXIT_FAILURE; 133 | } 134 | 135 | if (num_control_frames != 2) { 136 | fprintf(stderr, "%s: didn't get the right number of control frames\n", __func__); 137 | fprintf(stderr, "%s: num_control_frames = %d\n", 138 | __func__, num_control_frames); 139 | return EXIT_FAILURE; 140 | } 141 | 142 | for (;;) { 143 | if (!h) 144 | break; 145 | 146 | assert(h != NULL); 147 | assert(t != NULL); 148 | 149 | uint32_t len_wire, len; 150 | 151 | assert(t->len == sizeof(len_wire)); 152 | memmove(&len_wire, t->data, sizeof(len_wire)); 153 | len = ntohl(len_wire); 154 | 155 | assert(t->next != NULL); 156 | t = t->next; 157 | 158 | assert(len == t->len); 159 | assert(memcmp(h->data, t->data, len) == 0); 160 | 161 | t = t->next; 162 | h = h->next; 163 | } 164 | 165 | fprintf(stderr, "%s: all checks succeeded\n", __func__); 166 | 167 | /* cleanup */ 168 | 169 | h = h_head.next; 170 | for (;;) { 171 | if (!h) 172 | break; 173 | h_next = h->next; 174 | free(h->data); 175 | free(h); 176 | h = h_next; 177 | } 178 | 179 | t = t_head.next; 180 | for (;;) { 181 | if (!t) 182 | break; 183 | t_next = t->next; 184 | free(t->data); 185 | free(t); 186 | t = t_next; 187 | } 188 | 189 | return EXIT_SUCCESS; 190 | } 191 | 192 | int 193 | main(void) 194 | { 195 | fstrm_res res; 196 | struct fstrm_iothr *iothr = NULL; 197 | struct fstrm_iothr_options *iothr_opt = NULL; 198 | struct fstrm_iothr_queue *ioq = NULL; 199 | struct fstrm_rdwr *rdwr = NULL; 200 | struct fstrm_writer *w = NULL; 201 | struct fstrm_writer_options *wopt = NULL; 202 | 203 | rdwr = fstrm_rdwr_init(NULL); 204 | fstrm_rdwr_set_destroy(rdwr, test_rdwr_destroy); 205 | fstrm_rdwr_set_open(rdwr, test_rdwr_open); 206 | fstrm_rdwr_set_close(rdwr, test_rdwr_close); 207 | fstrm_rdwr_set_write(rdwr, test_rdwr_write); 208 | 209 | wopt = fstrm_writer_options_init(); 210 | res = fstrm_writer_options_add_content_type(wopt, 211 | test_content_type, 212 | strlen(test_content_type)); 213 | assert(res == fstrm_res_success); 214 | 215 | w = fstrm_writer_init(wopt, &rdwr); 216 | // 'rdwr' is now owned by 'w'. 217 | 218 | fstrm_writer_options_destroy(&wopt); 219 | 220 | iothr = fstrm_iothr_init(iothr_opt, &w); 221 | if (iothr == NULL) { 222 | fprintf(stderr, "fstrm_io_init() failed.\n"); 223 | fstrm_writer_destroy(&w); 224 | return EXIT_FAILURE; 225 | } 226 | // 'w' is now owned by 'iothr'. 227 | 228 | fstrm_iothr_options_destroy(&iothr_opt); 229 | 230 | ioq = fstrm_iothr_get_input_queue(iothr); 231 | if (ioq == NULL) { 232 | fprintf(stderr, "fstrm_iothr_get_input_queue() failed\n"); 233 | fstrm_iothr_destroy(&iothr); 234 | return EXIT_FAILURE; 235 | } 236 | 237 | for (int i = 0; i < num_iterations; i++) { 238 | char buf[100]; 239 | char *bytes; 240 | 241 | buf[0] = '\0'; 242 | sprintf(buf, "hello world #%d", i); 243 | 244 | h_cur->next = my_calloc(1, sizeof(*h_cur->next)); 245 | h_cur = h_cur->next; 246 | h_cur->len = strlen(buf); 247 | h_cur->data = my_strdup(buf); 248 | 249 | bytes = my_strdup(buf); 250 | 251 | for (;;) { 252 | res = fstrm_iothr_submit(iothr, ioq, bytes, strlen(bytes), 253 | fstrm_free_wrapper, NULL); 254 | if (res == fstrm_res_success) { 255 | break; 256 | } else if (res == fstrm_res_again) { 257 | poll(NULL, 0, 1); /* sleep for a millisecond */ 258 | continue; 259 | } else { 260 | free(bytes); 261 | fprintf(stderr, "fstrm_iothr_submit() failed\n"); 262 | fstrm_iothr_destroy(&iothr); 263 | return EXIT_FAILURE; 264 | } 265 | } 266 | } 267 | 268 | fstrm_iothr_destroy(&iothr); 269 | 270 | fprintf(stderr, "num_control_frames = %d\n", num_control_frames); 271 | 272 | return do_checks(); 273 | } 274 | --------------------------------------------------------------------------------